Goal

Analyze the adhesin properties of the Hyr/Iff-like (Hil) family in the Sacchromycetes This is version 4 of the analysis, using the expanded blast hits on 2022-05

Adhesin predictions

The goal of the first analysis is to assess the evidence for each Hil family member as encoding yeast adhesins. We rely on a ML-based prediction algorithm and the following known sequence features of adhesins: signal peptide + GPI-anchor, tandem repeats, high S/T frequency (possibly glycosylation)

Basic information

First get the basic information about the sequences in this study.

#sps.list <- c("Cduobushaemulonis","Cpseudohaemulonis","Chaemuloni","Cauris","Clusitaniae","Dhansenii","Cparapsilosis","Lelongisporus","Ctropicalis","Cdubliniensis","Calbicans","Sstipitis","Klactis","Ncastellii","Cglabrata","Nbracarensis","Ndelphensis","Nnivariensis")
blastInfo <- read_tsv("../data/expanded-blast-homologs-info.tsv", col_types = cols())# %>% 
#  mutate(species_id = factor(species, levels = sps.list), species = NULL)

ML adhesin predictions

FungalRV is a Support Vector Machine (SVM) based prediction algorithms that use sequence features such as amino acid composition (frequency, physiochemical properties etc.) as input and train Machine Learning models to distinguish fungal adhesins from non-adhesins.

frv.th = 0.511 # recommended FungalRV score threshold
frv <- read_tsv("../output/FungalRV/fungalRV-results.txt", skip = 3, col_names = c("name","frv.score"), col_types = "cd") %>% 
  mutate(name = str_sub(name, 2), frv.pred = frv.score > frv.th)
#if("frv.score" %in% names(seqInfo))
#  seqInfo <- select(seqInfo, -frv.score, -frv.pred, -faa.score, -faa.pred)
#seqInfo <- seqInfo %>% left_join(frv) %>% left_join(faa)

SP and GPI-anchor prediction

GPI-anchored proteins are characterized by an N-terminal signal peptide, which would direct the protein to the secretary pathway, and a C-terminal GPI-anchor peptide, which would be cleaved and replaced by the GPI-anchor, allowing the protein to be tethered to the cell wall.

For signal peptide, I used the SignalP server. Its latest version is 6.0.

# Signal peptide
gff.names <- c("name", "source", "type", "start", "end", "prob", "na1", "na2", "na3")
signalp6 <- read_tsv("../output/web-download/signalp_6.0_result.gff3", comment = "#", col_names = gff.names, col_types = "ccciidccc")

#if("signalp" %in% names(seqInfo))
#  seqInfo <- select(seqInfo, -signalp)
#
#seqInfo <- left_join(seqInfo, select(signalp5, name = id, prob), by = c("name" = "name")) %>% 
#  mutate(signalp = !is.na(prob)) %>% select(-prob)

For GPI-anchor prediction, I used the PredGPI server.

tmp <- read_delim("../output/web-download/predgpi-result-headline-only.txt", delim = "|", col_names = c("name","fp","omega"))
Rows: 215 Columns: 3── Column specification ───────────────────────────────────────────────────────────────────────
Delimiter: "|"
chr (3): name, fp, omega
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
pred.gpi <- tmp %>% 
  mutate(name = str_sub(name,2,-2), # remove > and the trailing space
         fp = as.numeric(str_sub(fp, 9, -2)), # extract the numeric part
         gpi.pred = fp <= 0.01,    # based on the cutoff of the PredGPI server (prob < 99% -> not GPI-anchored)
         omega = str_sub(omega, 8),
         cleaveRes = str_sub(omega, 1, 1),
         cleavePos = as.integer(str_sub(omega, 3))
         )
# remove the column if it already exists
#if("pred.gpi" %in% names(seqInfo))
#  seqInfo <- select(seqInfo, -pred.gpi)
#seqInfo <- left_join(seqInfo, select(pred.gpi, name, pred.gpi = is.gpi), by = c("name"="name"))

Combine the ML, SignalP and GPI-anchor predictions

adhesin <- blastInfo %>% 
  select(name, species, len = slen, pComplete) %>% 
  left_join(frv, by = "name") %>% 
  left_join(signalp6 %>% select(name, sp.prob = prob), by = "name") %>% 
  left_join(pred.gpi %>% select(name, gpi.pred, cleavePos), by = "name") %>% 
  mutate(sp.pred = !is.na(sp.prob)) %>% 
  relocate(c(frv.pred, sp.pred, gpi.pred), .after = pComplete)

Export the adhesin summary table

write_tsv(adhesin, file = "../output/table/20220818-Hil-family-size-adhesin-status-summary.tsv")

Plot the results alongside the species tree. First import the species tree

spsInfo <- read_tsv("../data/20220518-expanded-blast-species-info.tsv", col_types = cols())
sps.tree <- read.tree("../data/20220521-generax-species-tree.nwk") %>% 
  as_tibble() %>% 
  mutate(label = gsub("_", " ", label)) %>% 
  left_join(spsInfo, by = c("label" = "species")) %>% 
  as.treedata()
# to label the clades
clade <- c(
  MDR = MRCA(sps.tree, "Candida auris", "Candida duobushaemulonis"),
  CaLo = MRCA(sps.tree, "Candida parapsilosis", "Candida tropicalis"),
  glabrata = MRCA(sps.tree, "Candida glabrata", "Candida nivariensis")
)
sps.tree <- groupClade(sps.tree, clade)

Because we will plot the results separately, it is important to generate the species tree object and extract the order of the species, so as to match the numbers to the species.

p.tree <- ggtree(sps.tree, ladderize = FALSE) + xlim(0,2.2) + scale_y_reverse() +
  #geom_tiplab(aes(color = pathogen), as_ylab = TRUE) +
  geom_tiplab(size = 3.2, fontface = "italic", align = TRUE, linesize = 0.1, offset = 0.05) +
  geom_treescale(x = 0, width = 0.2, linesize = 1.2) +
  geom_hilight(node = clade["MDR"], fill = "#7F00FF", alpha = 0.15)  + # MDR
  geom_hilight(node = clade["CaLo"], fill = "pink", alpha = 0.25)    + # Candida/Lodderomyces
  geom_hilight(node = clade["glabrata"], fill = "steelblue", alpha = 0.15)  + # glabrata
  #geom_cladelabel(node = clade["MDR"],  label = "MDR", offset = 1.5,# color = "purple",
  #                offset.text = 0.05, angle = 270, hjust = .5, extend = 0.5) +# MDR
  #geom_cladelabel(node = clade["CaLo"],  label = "Candida/\nLodderomyces", offset = 1.47,# color = "hotpink2",
  #                offset.text = 0.1, angle = 270, hjust = .5, extend = 0.5, fontsize = 3.5) + # albicans
  #geom_cladelabel(node = clade["glabrata"],  label = "glabrata", offset = 1.38,# color = "steelblue", 
  #                offset.text = 0.05, angle = 270, hjust = .5, extend = 0.5) +# glabrata
  geom_tippoint(aes(color = pathogen)) +
  scale_color_manual(values =  c("crustacean" = "#6a5acd",
                                 "human" = "#d14949", 
                                 "human (rare)" = "steelblue",
                                 "no report" = "gray20")) +
  #guides(color = guide_legend(byrow = TRUE)) +
  theme(legend.position = c(0.12, 0.13))
Scale for 'y' is already present. Adding another scale for 'y', which will replace the
existing scale.

Summarize the results

df0 <- adhesin %>% 
  mutate(species = factor(species, levels = rev(get_taxa_name(p.tree)))) %>% 
  group_by(species) %>% 
  summarize(total = n(), FRV = sum(frv.pred), SP = sum(sp.pred), GPI = sum(gpi.pred), 
            final = sum(frv.pred & sp.pred & gpi.pred)) %>% 
  pivot_longer(total:final, names_to = "type", values_to = "number") %>% 
  mutate(type = factor(type, levels = unique(type))) %>% 
  # complete missing values for S. cerevisiae
  complete(species, type, fill = list(number = 0))

p <- ggplot(df0, aes(x = type, y = species)) + 
  scale_y_discrete(limits = rev) +
  geom_tile(aes(fill = number), color = "white", alpha = 0.4) +
  geom_text(aes(label = number), color = "black", size = 4) +
  scale_fill_distiller(palette = "Greys", direction = 1, limits = c(0, 20), oob = scales::squish) +
  scale_x_discrete(position = "top") +
  theme_cowplot() + theme(axis.title = element_blank(), axis.line = element_blank(), legend.position = "none")

ggsave(p, file = paste0("../output/img/",gsub("-", "", Sys.Date()), "-species-adhesin-prediction-summary.png"), width = 5, height = 7)
p1 <- p + theme(axis.text.y = element_blank(), axis.ticks.y = element_blank())
plot_grid(p.tree, p1, rel_widths = c(3,2), scale = c(1, 0.95))

Summarize the % of Hil genes passing all three tests

df0 %>% pivot_wider(names_from = "type", values_from = "number") %>% 
  select(species, total, final) %>% 
  summarize(total = sum(total), adhesin = sum(final))

Short or no GPI-anchor

A subset of the identified Hil homologs are short and/or missing either the signal peptide or the GPI anchor. We need to first filter out ones that are incomplete (sequence record) before examining the remaining ones.

First, check the protein length distribution. M. bicuspidata is an outlier in that 27 of the 29 Hil homologs in this species are shorter than 500 aa and 10 were annotated as being incomplete in the RefSeq database.

adhesin %>% 
  mutate(`M. bicuspidata` = species == "Metschnikowia bicuspidata",
         protein = ifelse(grepl("no", pComplete), "Incomplete", "Complete")) %>% 
  ggplot(aes(x = len, fill = `M. bicuspidata`)) + 
  geom_histogram(binwidth = 100) + 
  geom_vline(xintercept = 600, linetype = 2, color = "gray20") +
  scale_fill_manual(values = c("gray50", "red3")) +
  facet_wrap(~protein, nrow = 2, labeller = "label_both") +
  xlab("Protein length") + ylab("Frequency") +
  theme_cowplot() + theme(legend.title = element_text(face = 3))
ggsave(file = "../output/img/20221002-homologs-length-distribution-Mb.png", width = 6, height = 4)

Filter out incomplete entries and focus on those that either are short or miss SP/GPI

# short and missing SP/GPI
adhesin %>% 
  filter(!grepl("no", pComplete), len < 600, len > 250) %>% 
  group_by(sp.pred, gpi.pred, species) %>% 
  summarize(n = n(), .groups = "drop") %>% 
  mutate(group = paste0(ifelse(sp.pred, "SP+", "sp-"), ifelse(gpi.pred, "GPI+", "gpi-"))) %>% 
  select(group, species, n) %>% 
  pivot_wider(names_from = group, values_from = n, values_fill = 0) %>% 
  mutate(total = rowSums(across(`sp-gpi-`:`SP+GPI+`), na.rm = TRUE)) %>% 
  arrange(desc(total)) %>% 
  write_tsv(file = "../output/table/20221003-short-and-missing-SP-GPI.tsv")

# long and missing SP/GPI
adhesin %>% 
  filter(!grepl("no", pComplete), len >= 600) %>% 
  group_by(sp.pred, gpi.pred, species) %>% 
  summarize(n = n(), .groups = "drop") %>% 
  mutate(group = paste0(ifelse(sp.pred, "SP+", "sp-"), ifelse(gpi.pred, "GPI+", "gpi-"))) %>% 
  select(group, species, n) %>% 
  pivot_wider(names_from = group, values_from = n, values_fill = 0) %>% 
  mutate(total = rowSums(across(`sp-gpi-`:`SP+GPI+`), na.rm = TRUE)) %>% 
  arrange(desc(total)) %>% 
  write_tsv(file = "../output/table/20221003-long-and-missing-SP-GPI.tsv")

# all length
adhesin %>% 
  filter(!grepl("no", pComplete)) %>% 
  mutate(length = cut(len, breaks = c(0, 250, 600, 5000), labels = c("0-250", "251-600", ">600"))) %>% 
  group_by(sp.pred, gpi.pred, length) %>% 
  summarize(n = n(), .groups = "drop") %>% 
  mutate(group = paste0(ifelse(sp.pred, "SP+", "sp-"), ifelse(gpi.pred, "GPI+", "gpi-"))) %>% 
  select(group, length, n) %>% 
  pivot_wider(names_from = group, values_from = n, values_fill = 0) %>% 
  mutate(total = rowSums(across(`sp-gpi-`:`SP+GPI+`), na.rm = TRUE)) %>% 
  arrange(desc(total)) %>% 
  write_tsv(file = "../output/table/20221003-all-missing-SP-GPI.tsv")
  

Feature map for homologs

The goal is to produce a schematic plot for each homolog outlining their main features, such as the locations of the PFam domains (mainly the Hyp_reg_CWP), locations of the signal peptide and GPI-anchor, distribution of TANGO sequences. Note that all these features can be represented as a range with associated metadata. So the first step is to collect the coordinates of the features

Gene tree for organizing the features

# load the gene tree
gene.tree <- read.nhx(file = "../data/20220512-generax-clustalo-shen2018-wScer-gene-tree.nhx") %>% 
  drop.tip(tip = Mb.rm$name)
# add supplemental information
clades <- sps.tree %>% as_tibble() %>% select(treeName, group) %>% na.omit()
gene.tree <- left_join(gene.tree, select(spsInfo, treeName, family), by = c("S" = "treeName")) %>% 
  left_join(clades, by = c("S" = "treeName"))# %>% 
  #mutate(family = forcats::fct_relevel(family, "Metschnikowiaceae", after = Inf))
# label selected species to show the clustering
selected_nodes <- gene.tree %>% as_tibble() %>% 
  filter(S %in% c("Candida_albicans", "Candida_glabrata", "Candida_auris")) %>% 
  pull(node)
# color by family
clade.cols <- c(
  "CaLo" = "firebrick",
  "MDR" = "#7F00FF",
  "glabrata" = "steelblue"
)
p.gene.tree <- ggtree(gene.tree, size = 0.4) + xlim(0,4) + 
  #geom_nodepoint(aes(fill = D), data = td_filter(D == "Y"), shape = 21, size = 1, color = "red") + 
  geom_tippoint(aes(color = group), size = 1) +
  geom_tiplab(aes(color = family),
               align = TRUE, linesize = 0.1, size = 1, offset = 0.05) +
  geom_nodelab(aes(x = branch, label = node), size = 1) +
  #geom_cladelab(node = 357,  label = "M. bicuspidata", offset.text = 0.05, angle = 270, hjust = .5, extend = 0.5) +
  #geom_text(label = "D", data = td_filter(D == "Y"), hjust = -0.4, size = 1.5, color = "red")# +

  scale_color_manual(name = "Clade", values = clade.cols)# +
p.gene.tree

ggsave(filename = "../output/img/20220916-gene-tree-side.png", width = 5, height = 7)

Extract gene tree order

genetreeOrder <- get_taxa_name(p.gene.tree)

Organize and combine the tandem repeats features

# summarize stats of tandem repeats
repeats <- tandem %>% 
  group_by(type, period) %>% 
  summarize(n = n(), copyMean = mean(copyN), .groups = "drop") %>% 
  mutate(length = period * copyMean)

tr <- tandem %>% 
  left_join(select(repeats, type, copyMean), by = c("type" = "type")) %>% 
  filter(name %in% genetreeOrder) %>% 
  mutate(type = paste0("TR-", type),
         tip = paste0(consensus_nogap,
                      "\ntype: ", type,
                      "\nperiod: ", period, 
                      "\ncopyN: ", copyMean),
         name = ordered(name, levels = rev(genetreeOrder))) %>% 
  select(name, type, start, end, tip)

Make a seqLen object to draw the overall length of each protein

seqLen <- blastInfo %>% 
  mutate(start = 1, name = ordered(name, levels = rev(genetreeOrder))) %>% 
  select(name, start, end = slen)
# GPI-anchor
# use pred.gpi
# feature set
# structure: id  feature  start  end
feature <- bind_rows(
  Hyphal_reg_CWP = pf11765,
  # extend the signal peptide segment by 10 amino acids to make it more visible
  `Signal Peptide` = signalp6 %>% mutate(end = end + 10) %>% select(name, start, end),
  # extend the GPI-anchor C-terminus segment by 20 amino acids to make it more visible
  `GPI-anchor` = pred.gpi %>% filter(gpi.pred) %>%
    left_join(select(blastInfo, name, slen), by = "name") %>% 
    mutate(start = cleavePos-10, end = slen) %>% 
    select(name, start, end),
  `Tandem Repeats` = tr %>% select(name, start, end),
  .id = "type"
) %>% filter(!name %in% Mb.rm$name)

feature <- feature %>% 
  mutate(name = ordered(name, levels = rev(genetreeOrder)),
         type = ordered(type, levels = c("Hyphal_reg_CWP", "Signal Peptide", "GPI-anchor", "Tandem Repeats")))
feature.colors <- c("Hyphal_reg_CWP" = "#3d85c6", "Signal Peptide" = "#cc0000", "GPI-anchor" = "#6a3d9a", "Tandem Repeats" = "#af8400bb")

Plot domain organization

h = 1.2
# plot
p0 <- ggplot(seqLen, aes(x = name, y = start, xend = name, yend = end)) + 
  geom_segment(color = "gray80", size = h)
p1 <- geom_segment(data = feature,  aes(color = type), size = h)
p2 <- geom_segment(data = tandem.div, aes(x = name, xend = name, y = div, yend = div + 1.5),
                   size = h, color = "white")
p3 <- p0 + p1 + coord_flip() + theme_classic() + 
  scale_color_manual(values = feature.colors) +
  scale_y_continuous(expand = expansion(mult = c(0.02, 0.02))) +
  theme(axis.text.y = element_text(size = 3), axis.title.y = element_blank(),
        axis.line.y = element_blank(), axis.ticks.y = element_blank(),
        axis.line.x = element_blank(),# axis.ticks.x = element_blank(),
        legend.position = c(0.8, 0.9), 
        legend.text = element_text(size = 12), legend.title = element_text(size = 14),
        plot.title = element_text(hjust = 0.5), 
        panel.background = element_rect(fill = alpha("lightblue",0.1))) +
  labs(y = "Position in sequence", x = "Sequences", color = "FEATURES")
#plot_grid(p.gtree, p3, ncol = 2, align = 'v', rel_widths = c(1,2), scale = c(1.01,1))
ggsave("../output/img/20220916-domain-tandem-repeats.png", plot = p3, width = 6, height = 7.5)

Fig. ? Blue boxes indicate the PF11765 domains while all other non-grey boxes indicate XSTREAM-determined tandem repeat domains. Colors are used to group highly similar tandem repeats. The black thin lines demarcate adjacent tandem repeat units. The table below shows the copy number, period and consensus sequence for each tandem domain organized by the host sequences.

Separate TR types

#DT::datatable(
#  tandem %>% 
#    dplyr::rename(seqL = seqLength, err = consensus_error, seq = consensus_nogap) %>% 
#    select(-seqAlign, -type, -consensus_gap, -seq, seq) %>% 
#    arrange(desc(name)),
#  fillContainer = FALSE, options = list(pageLength = 10)
#)

Repeat the above analysis but distinguishing between all different TR types

require(RColorBrewer)
Loading required package: RColorBrewer
tr.th <- 100 # arbitrary threshold for distinguishing "short" from "long" TRs
tr.col <- character(nrow(repeats)) # create a color vector
short.rp <- which(repeats$length < tr.th) # identify the short repeats indices
long.rp <- setdiff(1:nrow(repeats), short.rp) # the long repeats indices
set.seed(123) # for reproducibly shuffling the order before assigning the colors
short.rp <- sample(short.rp) # shuffle the indices for short tandem repeats
tr.col[short.rp] <- colorRampPalette(brewer.pal(12, "Paired")[seq(3,11,by=2)])(length(short.rp)) # assign the short repeats a lower contrast color
set.seed(231) # for reproducibly shuffling the order before assigning the colors
long.rp <- sample(long.rp)
tr.col[long.rp] <- colorRampPalette(brewer.pal(12, "Paired")[seq(4,12,by=2)])(length(long.rp)) # assign the long repeats a higher contrast color
# -- desaturate the colors -- 
# https://stackoverflow.com/questions/26314701/r-reducing-colour-saturation-of-a-colour-palette
library(colorspace)   ## hsv colorspace manipulations

## Function for desaturating colors by specified proportion
desat <- function(cols, sat=0.5) {
    X <- diag(c(1, sat, 1)) %*% rgb2hsv(col2rgb(cols))
    hsv(X[1,], X[2,], X[3,])
}

tr.col <- desat(tr.col, sat = 0.8)
# -- finish --
tr.col <- paste0(tr.col, "CC") # add 20% transparency to the TR features
names(tr.col) <- paste0("TR-", repeats$type) # name the colors by the TR types
repeats$color <- tr.col

Combine domains, SP and GPI-anchor with TR features.

# combine sequence features with tandem repeats
feature1 <- bind_rows(filter(feature, type != "Tandem Repeats"), tr) %>% 
  mutate(type = ordered(type, levels = c("Hyphal_reg_CWP", "SignalP", "GPI-anchor", unique(tr1$type))))
Error in `mutate()`:
! Problem while computing `type = ordered(...)`.
Caused by error in `h()`:
! error in evaluating the argument 'x' in selecting a method for function 'unique': object 'tr1' not found
Backtrace:
  1. ... %>% ...
 10. base::.handleSimpleError(`<fn>`, "object 'tr1' not found", base::quote(unique(tr1$type)))
 11. base h(simpleError(msg, call))
# plot
p1 <- geom_segment(data = feature1, aes(color = type, text = tip), size = h)
p2 <- geom_segment(data = tandem.div, aes(x = name, xend = name, y = div, yend = div + 1.5),
                   size = h, color = "white")
p3 <- p0 + p1 + coord_flip() + theme_classic() + 
  scale_color_manual(values = feature.col1) +
  scale_y_continuous(expand = expansion(mult = c(0.02, 0.02))) +
  theme(axis.text.y = element_text(size = 3), axis.title.y = element_blank(),
        axis.line.y = element_blank(), axis.ticks.y = element_blank(),
        axis.line.x = element_blank(),# axis.ticks.x = element_blank(),
        legend.position = "none", plot.title = element_text(hjust = 0.5),
        panel.background = element_rect(fill = alpha("lightblue",0.1))) +
  labs(y = "Position in sequence", x = "Sequences", color = "FEATURES")
# plot_grid(p.gtree, p3 + p2, ncol = 2, align = 'v', rel_widths = c(1,2), scale = c(1.01,1))
ggsave("../output/img/20220916-domain-tandem-repeats-distinct-color.png", plot = p3, width = 5, height = 7.5)
# plot
#require(plotly)
plotly::ggplotly(p3, tooltip = "text", width = 900, height = 900)
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     

Tango predicted β-aggregation sequences

# reorder the sequences for plotting
# plot
#p1 <- ggplot(seqLen, aes(x = name, y = start, xend = name, yend = end)) + geom_segment(color = "gray80", size = 2)
p1 <- geom_segment(data = filter(pf11765, !name %in% Mb.rm$name), 
                   aes(x = name, xend = name, y = start+1, yend = end), size = h, color = "#3d84c6")
p2 <- geom_segment(data = filter(tango, !name %in% Mb.rm$name), 
                   aes(x = name, xend = name, y = ifelse(start-4 >= 0, start-4, 0), yend = end + 4, color = median), size = h)
p3 <- p0 + p1 + p2 + coord_flip() + theme_classic() + 
  scale_color_viridis_c(limits = c(5,101), breaks = c(5,seq(25,100,25)), direction = -1) +
  theme(axis.text.y = element_text(size = 4), axis.title.y = element_blank(),
        axis.line.y = element_blank(), axis.ticks.y = element_blank(),
        axis.line.x = element_blank(), axis.ticks.x = element_blank(),
        plot.title = element_text(hjust = 0.5),
        legend.position = c(0.8,0.88),
        legend.title = element_text(size = 14),
        legend.text = element_text(size = 12),
        panel.background = element_rect(fill = alpha("lightblue",0.1))) +
  ylim(-2, 4500) + labs(y = "Position in sequence", x = "Sequences", color = "TANGO score")
p3

##plot_grid(p.gtree, p4, ncol = 2, align = 'v', rel_widths = c(1,2.5), scale = c(1.01,1))
ggsave("../output/img/20220916-tango-score-segment.png", plot = p3, width = 6, height = 7.5)

To compare the number of TANGO motifs in C. auris Hil1-4 and their close homologs to the rest of the Hil family, we first identify the first group of sequences

a <- which(genetreeOrder == "XP_025344416.1_Candida_haemuloni", arr.ind = TRUE)
b <- which(genetreeOrder == "XP_024716365.1_Candida_pseudohaemulonii", arr.ind = TRUE)
hil1_4_mdr <- genetreeOrder[a:b]
rm(list = c("a", "b"))
motif.per.seq %>% 
  select(name, n.all) %>% 
  mutate(group = ifelse(name %in% hil1_4_mdr, "Hil1-4_MDR", "others")) %>% 
  group_by(group) %>% 
  summarize(median = median(n.all))

Discussion

  • The one sequence below 500 a.a. is from N. delphensis, which is labeled as a partial CDS.
  • Majority of the proteins in the list are 500-2000 a.a., with a few exceptionally long
  • Not only do Saccharomycetaceae species have fewer Hil family homologs, the ones they have are also short (< 1000 a.a.) with the exception of C. glabrata

Chromosomal locations

Are members of this protein family enriched in the subtelomeric regions?

A recent long-read sequencing study for C. glabrata annotated 31 novel ORFs, of which 24 are GPI-Cell Wall Proteins. The authors cited previous literature supporting the in the subtelomeric regions Xu 2020. While performing BLAST on FungiDB to identify homologs of our protein, I also noticed that many of the hits appear to be at the beginning and end of the chromosomes.

To test if there is indeed a significant enrichment among this family of proteins in the subtelomeric regions, I collected the chromosomal locations for a subset of the species whose genomes were assembled to a chromosomal or complete genome level (the two are somewhat equivalent). These include Candida albicans, Candida auris, Candida dubliniensis, Candida orthopsilosis, Debaryomyces hansenii, Kazachstania africana, Kazachstania naganishii, Kluyveromyces lactis, Naumovozyma castellii, Naumovozyma dairenensis, Candida glabrata, Scheffersomyces stipitis

To formally test this hypothesis, I need to account for the background gene density differences along the chromosomes. The idea is to compare the chromosomal positions for this group of proteins compared with the gene densities on the chromosomes they reside on.

One consideration for this analysis is that if we simply use all the species for which a well assembled genome is available, we may end up over-sampling a phylogenetic clade and having its Hil family’s localization over-weighted in the final test. To avoid giving too much weight on a group of species, I will select a representative species if more than one is available in a relatively closely related clade. For example, we will use Candida albicans and remove Candida dubliniensis.

# import the chromosomal location information
chrLoc <- read_tsv("../data/20220919-expanded-blast-chromosomal-locations.tsv", col_types = cols())
# decide the species to be used for the analysis
use.sps <- c("Candida albicans", "Debaryomyces hansenii", "Candida orthopsilosis",
             "Kazachstania africana", "Kluyveromyces lactis",
             "Naumovozyma dairenensis", "Candida auris", "Candida glabrata")
# create a new tibble for our homologs from these species
fg.freq <- chrLoc %>% filter(species %in% use.sps)
# import assembly info
assembly.info <- read_tsv("../data/20220525-expanded-blast-species-assembly-info.tsv",
                          col_types = cols())
use.sps <- assembly.info %>% 
  filter(species %in% use.sps) %>%
  filter(!species %in% c("Candida glabrata", "Candida auris", "Kluyveromyces lactis")) %>% 
  select(species, assembly = assemblyaccession) %>% 
  # manually add several species. note that we are using the B11245 (Clade 4) strain to 
  # represent C. auris, because it is assembled to a chromosome level and has annotation files
  add_row(species = c("Candida glabrata", "Candida auris", "Kluyveromyces lactis"),
          assembly = c("GCA_010111755.1", "GCA_008275145.1", "GCF_000002515.2"))

To conduct this test, we first need to prepare and compute the background gene densities. To do this, we will gather the genome assembly files for the selected species, read them into R, and generate a table that contains one row for each gene, with its gene ID, chromosome number, chromosome length and the start position expressed as a percentage measured from the chromosome ends.

# 1. prepare file names
#   get all file names that ends with "feature_table.txt.gz", which contain the gene annotation
feature.files <- list.files(path = "../data/assembly-info/", pattern = "*feature_table.txt.gz$")
names(feature.files) <- sapply(str_split(feature.files, pattern = "_"), function(x) {
  paste(x[1], x[2], sep = "_")
})
# get all file names that ends with "assembly_report.txt", which contain the chromosomal length
assembly.files <- list.files(path = "../data/assembly-info/", pattern = "*assembly_report.txt$")
names(assembly.files) <- sapply(str_split(assembly.files, pattern = "_"), function(x) {
  paste(x[1], x[2], sep = "_")
})
use.sps$FeatureFile <- feature.files[use.sps$assembly]
use.sps$AssemblyFile <- assembly.files[use.sps$assembly]
# 2. read in the assembly information
feature.col.names <- c("feature","class","assembly","assembly_unit","seq_type","chromosome","genomic_accession","start","end","strand","product_accession","non_redundant_refseq","related_accession","name","symbol","GeneID","locus_tag","feature_interval_length","product_length","attributes")
assembly.col.names <- c("chromosome","seq_role","assign_molecule","type","gb_acc","relationship",
                        "refseq_acc","assembly_unit","seqL","ucsc_name")
compute.bg.freq <- function(row){
  assembly.file <- row["AssemblyFile"]
  assembly <- read_tsv(paste0("../data/assembly-info/",assembly.file), comment = "#",
                       col_names = assembly.col.names, col_types = "ccccccccic")
  feature.file <- row["FeatureFile"]
  feature <- read_tsv(paste0("../data/assembly-info/",feature.file), col_names = feature.col.names,
                      col_types = "ccccccciicccccccciic", skip = 1)
  res <- feature %>% 
    filter(feature == "mRNA") %>% 
    # these feature tables are organized hierarchically, with the top level being "gene"
    # the next level one of "mRNA", "ncRNA", "tRNA" or "rRNA". we only count protein-coding genes, i.e.
    # "mRNA". the reason I didn't select the "CDS" feature type is because in a small number of cases,
    # one mRNA feature contains more than one CDS feature, possibly due to splicing or alternative 
    # translational start site
    select(chromosome, start, end) %>% 
    left_join(assembly %>%
                mutate(chraccver = ifelse(refseq_acc != "na", refseq_acc, gb_acc)) %>% 
                select(chromosome, chraccver, seqL), 
              by = c("chromosome" = "chromosome")) %>%
    mutate(relLoc = round(start / seqL, 3))
  return(res)
}
# 3. apply the function to the genomes, but leave out C. auris
bg.freq <- apply(use.sps, MARGIN = 1, compute.bg.freq)
names(bg.freq) <- use.sps$species

Let’s take a look at the gene density in one of the genomes, e.g. D. hansenii

Below I use the geom_histogram function instead, with breaks specified manually. This results in a density distribution that is pretty flat across the chromosomes.

bg.freq$`Debaryomyces hansenii` %>% ggplot(aes(x = relLoc)) + 
  geom_histogram(breaks = seq(0,1,0.05)) +
  facet_wrap(~ chromosome) + ggtitle("D. hansenii") + theme(plot.title = element_text(hjust = 0.5))

In order to compare the distribution of all genes in different bins of the chromosomes to the homologs in our case study, we can divide each chromosome in the nrow(use.sps) genomes into an arbitrary number of bins after “folding” them in half, e.g. 0-10%, 10-20%, 20-30%, 30-40% and 40-50%. To be able to visually compare the distribution of our homologs and the genome background, we will create a special “chromosome” class that will be our homologs and combine them with the bg.freq table.

freq.bins <- c(-0.001, seq(0.1, 0.5, 0.1)); freq.binsL <- c(0, freq.bins[-1])
freq.label <- paste0(head(freq.binsL, -1)*100,"-",tail(freq.binsL, -1)*100,"%")
bg.freq.tb <- bind_rows(bg.freq, .id = "species") %>% 
  mutate(fold.relLoc = ifelse(relLoc <= 0.5, relLoc, 1-relLoc),
         bin = cut(fold.relLoc, breaks = freq.bins, labels = freq.label))

# add the homologs
fg.freq <- fg.freq %>% 
  mutate(fold.relLoc = ifelse(relLoc <= 0.5, relLoc, 1-relLoc),
         bin = cut(fold.relLoc, breaks = freq.bins, labels = freq.label)) 
freq.plot <- fg.freq %>%
  mutate(chromosome = "Hil") %>%  # we label the homologs as Hil to make it a separate class
  select(species = species, chromosome, bin) %>% 
  bind_rows(select(bg.freq.tb, species, chromosome, bin)) %>% 
  mutate(chromosome = ordered(chromosome, levels = c(1:12,LETTERS[1:13],"Hil"))) %>% 
  group_by(species) %>% 
  filter(sum(chromosome == "Hil") >=3) # remove species that have fewer than 3 Hil homologs
# plot
freq.plot %>% 
  #mutate(species = paste0(substr(species, 1, 1), ". ", substr(species, 2, 15))) %>% 
  ggplot(aes(x = chromosome, group = bin, fill = bin)) + 
  geom_bar(position = position_fill()) +
  facet_wrap(~ species, scales = "free_x", ) + 
  #scale_fill_brewer("Distance from\nchromosome end", type = "qual", palette = 3) +
  scale_fill_viridis_d(direction = -1, end = 0.95, alpha = 0.9) +
  scale_y_continuous(name = "Cumulative % of genes", trans = "reverse", breaks = seq(0,1,0.2)) + 
  theme_cowplot() + panel_border(color = "grey80") +
  theme(legend.position = "none", strip.background = element_blank(),
        strip.text.x = element_text(face = 3),
        axis.text = element_text(size = rel(0.7)))

ggsave("../output/img/20220920-compare-homologs-chromosomal-locations-to-bg.png", width = 7, height = 4)

In the plot above, we can see that the distribution of the Hil proteins on the chromosome deviate from the background. Only species with three or more Hil family members are shown here.

Now that we have the background gene frequencies computed, we can start constructing a test that tests for significant departure in the chromosomal locations of our protein family from the background frequencies. One idea is to divide the chromosome into equal-sized bins and use the frequencies of all genes in each bin as the multinomial probabilities in the null hypothesis. If our proteins were randomly selected from each chromosome without regard to their location, we would expect their locations to conform to the background frequencies. This can be tested using an exact multinomial test or an approximate Chi-square test or G-test. Since we don’t distinguish the two ends of a chromosome, we can “fold” the chromosome “in half” and measure each gene’s location as a percentage from the closer end, i.e. the relative location ranging from 0%-50%. If we can reject the null hypothesis, that constitutes evidence that the proteins from our group are not randomly selected from the background set.

Result of multinomial test

# install XNomial package for the multinomial exact test function
# https://cran.r-project.org/web/packages/XNomial/vignettes/XNomial.html#e1
while(!require(XNomial))
  suppressMessages(install.packages("XNomial"))
Loading required package: XNomial
# calculate pooled background frequency
bg.cnt <- tabulate(bg.freq.tb$bin)
fg.cnt <- tabulate(fg.freq$bin)
xmulti(obs = fg.cnt, expr = bg.cnt, detail = 3)

P value  (LLR)  =  1.301e-12
P value (Prob)  =  4.7e-13
P value (Chisq) =  2.359e-13

Observed:  34 7 2 8 1 
Expected ratio:  8602 9027 9021 9090 9028 
Total number of tables:  367290 

Note that the three P-values correspond to three approaches of testing the goodness-of-fit. The LLR, which stands for Log Likelihood Ratio, is generally preferred. But all three said the same thing: the observation deviates from the background frequency significantly. By looking at the plots above, it is clear that the deviation is due to the excess of our homologs residing in the 0-10% bin, which is the tip of the chromosomes.

The test above assumes that the gene density along all chromosomes in the eight species follow the same distribution. The empirical observation supports that hypothesis. Should that to be not the case, we could also account for the variability in gene density distribution between species or even between chromosomes within a species. The idea is to first collect the chromosomes that our homologs come from, and then randomly sample the same number of genes as the number of our homologs on that chromosome. Do this for all of the homolog-containing chromosomes, we would obtain one random sample. Repeat this process 1000 times or more, we will then get the pseudosample, which we can use to compare with our observations. Here we need to come up with a statistic that summarizes each of our observation or pseudosample. For example, we could calculate the median % location for each sample, and ask where our observation lie relative to the pseudosamples. I’ll skip this approach for now since the first appraoch appears to be OK given the similar gene density distribution across chromosomes and species.

LS0tCnRpdGxlOiAiQW5hbHl6ZSBYUF8wMjg4ODkwMzMgZmFtaWx5IGV2b2x1dGlvbiBhbmQgYWRoZXNpbiBwcm9wZXJ0aWVzIgphdXRob3I6ICJCaW4gSGUiCmRhdGU6ICIyMDIyLTA2LTEyICh1cGRhdGVkIGByIFN5cy5EYXRlKClgKSIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogICAgdG9jX2RlcHRoOiA1CiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKCmBgYHtyIGxvYWRfbGlicmFyaWVzLCBlY2hvID0gRkFMU0V9CiNpZiAoIXJlcXVpcmVOYW1lc3BhY2UoInRyZWVpbyIsIHF1aWV0bHkgPSBUUlVFKSkKIyAgICBCaW9jTWFuYWdlcjo6aW5zdGFsbCgidHJlZWlvIikKI2lmICghcmVxdWlyZU5hbWVzcGFjZSgiZ2d0cmVlIiwgcXVpZXRseSA9IFRSVUUpKQojICAgIEJpb2NNYW5hZ2VyOjppbnN0YWxsKCJnZ3RyZWUiKQojaWYgKCFyZXF1aXJlTmFtZXNwYWNlKCJHZW5vbWljUmFuZ2VzIiwgcXVpZXRseSA9IFRSVUUpKQojICAgIEJpb2NNYW5hZ2VyOjppbnN0YWxsKCJHZW5vbWljUmFuZ2VzIikKc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkodGlkeXZlcnNlKSkKc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkoY293cGxvdCkpCnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KGdndHJlZSkpCnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KHRyZWVpbykpCnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhyZXF1aXJlKEdlbm9taWNSYW5nZXMpKQpgYGAKCiMgR29hbAoKQW5hbHl6ZSB0aGUgYWRoZXNpbiBwcm9wZXJ0aWVzIG9mIHRoZSBIeXIvSWZmLWxpa2UgKEhpbCkgZmFtaWx5IGluIHRoZSBTYWNjaHJvbXljZXRlcwpUaGlzIGlzIHZlcnNpb24gNCBvZiB0aGUgYW5hbHlzaXMsIHVzaW5nIHRoZSBleHBhbmRlZCBibGFzdCBoaXRzIG9uIDIwMjItMDUKCiMgQWRoZXNpbiBwcmVkaWN0aW9ucwpUaGUgZ29hbCBvZiB0aGUgZmlyc3QgYW5hbHlzaXMgaXMgdG8gYXNzZXNzIHRoZSBldmlkZW5jZSBmb3IgZWFjaCBIaWwgZmFtaWx5IG1lbWJlciBhcyBlbmNvZGluZyB5ZWFzdCBhZGhlc2lucy4gV2UgcmVseSBvbiBhIE1MLWJhc2VkIHByZWRpY3Rpb24gYWxnb3JpdGhtIGFuZCB0aGUgZm9sbG93aW5nIGtub3duIHNlcXVlbmNlIGZlYXR1cmVzIG9mIGFkaGVzaW5zOiBzaWduYWwgcGVwdGlkZSArIEdQSS1hbmNob3IsIHRhbmRlbSByZXBlYXRzLCBoaWdoIFMvVCBmcmVxdWVuY3kgKHBvc3NpYmx5IGdseWNvc3lsYXRpb24pCgojIyBCYXNpYyBpbmZvcm1hdGlvbgpGaXJzdCBnZXQgdGhlIGJhc2ljIGluZm9ybWF0aW9uIGFib3V0IHRoZSBzZXF1ZW5jZXMgaW4gdGhpcyBzdHVkeS4KYGBge3IgbG9hZF9zZXFfaW5mb30KI3Nwcy5saXN0IDwtIGMoIkNkdW9idXNoYWVtdWxvbmlzIiwiQ3BzZXVkb2hhZW11bG9uaXMiLCJDaGFlbXVsb25pIiwiQ2F1cmlzIiwiQ2x1c2l0YW5pYWUiLCJEaGFuc2VuaWkiLCJDcGFyYXBzaWxvc2lzIiwiTGVsb25naXNwb3J1cyIsIkN0cm9waWNhbGlzIiwiQ2R1YmxpbmllbnNpcyIsIkNhbGJpY2FucyIsIlNzdGlwaXRpcyIsIktsYWN0aXMiLCJOY2FzdGVsbGlpIiwiQ2dsYWJyYXRhIiwiTmJyYWNhcmVuc2lzIiwiTmRlbHBoZW5zaXMiLCJObml2YXJpZW5zaXMiKQpibGFzdEluZm8gPC0gcmVhZF90c3YoIi4uL2RhdGEvZXhwYW5kZWQtYmxhc3QtaG9tb2xvZ3MtaW5mby50c3YiLCBjb2xfdHlwZXMgPSBjb2xzKCkpIyAlPiUgCiMgIG11dGF0ZShzcGVjaWVzX2lkID0gZmFjdG9yKHNwZWNpZXMsIGxldmVscyA9IHNwcy5saXN0KSwgc3BlY2llcyA9IE5VTEwpCmBgYAoKIyMgTUwgYWRoZXNpbiBwcmVkaWN0aW9ucwpbRnVuZ2FsUlZdKGh0dHA6Ly9mdW5nYWxydi5pZ2liLnJlcy5pbi8pIGlzIGEgU3VwcG9ydCBWZWN0b3IgTWFjaGluZSAoU1ZNKSBiYXNlZCBwcmVkaWN0aW9uIGFsZ29yaXRobXMgdGhhdCB1c2Ugc2VxdWVuY2UgZmVhdHVyZXMgc3VjaCBhcyBhbWlubyBhY2lkIGNvbXBvc2l0aW9uIChmcmVxdWVuY3ksIHBoeXNpb2NoZW1pY2FsIHByb3BlcnRpZXMgZXRjLikgYXMgaW5wdXQgYW5kIHRyYWluIE1hY2hpbmUgTGVhcm5pbmcgbW9kZWxzIHRvIGRpc3Rpbmd1aXNoIGZ1bmdhbCBhZGhlc2lucyBmcm9tIG5vbi1hZGhlc2lucy4KYGBge3IgYWRoZXNpbl9wcmVkaWN0aW9ufQpmcnYudGggPSAwLjUxMSAjIHJlY29tbWVuZGVkIEZ1bmdhbFJWIHNjb3JlIHRocmVzaG9sZApmcnYgPC0gcmVhZF90c3YoIi4uL291dHB1dC9GdW5nYWxSVi9mdW5nYWxSVi1yZXN1bHRzLnR4dCIsIHNraXAgPSAzLCBjb2xfbmFtZXMgPSBjKCJuYW1lIiwiZnJ2LnNjb3JlIiksIGNvbF90eXBlcyA9ICJjZCIpICU+JSAKICBtdXRhdGUobmFtZSA9IHN0cl9zdWIobmFtZSwgMiksIGZydi5wcmVkID0gZnJ2LnNjb3JlID4gZnJ2LnRoKQojaWYoImZydi5zY29yZSIgJWluJSBuYW1lcyhzZXFJbmZvKSkKIyAgc2VxSW5mbyA8LSBzZWxlY3Qoc2VxSW5mbywgLWZydi5zY29yZSwgLWZydi5wcmVkLCAtZmFhLnNjb3JlLCAtZmFhLnByZWQpCiNzZXFJbmZvIDwtIHNlcUluZm8gJT4lIGxlZnRfam9pbihmcnYpICU+JSBsZWZ0X2pvaW4oZmFhKQpgYGAKCiMjIFNQIGFuZCBHUEktYW5jaG9yIHByZWRpY3Rpb24KR1BJLWFuY2hvcmVkIHByb3RlaW5zIGFyZSBjaGFyYWN0ZXJpemVkIGJ5IGFuIE4tdGVybWluYWwgc2lnbmFsIHBlcHRpZGUsIHdoaWNoIHdvdWxkIGRpcmVjdCB0aGUgcHJvdGVpbiB0byB0aGUgc2VjcmV0YXJ5IHBhdGh3YXksIGFuZCBhIEMtdGVybWluYWwgR1BJLWFuY2hvciBwZXB0aWRlLCB3aGljaCB3b3VsZCBiZSBjbGVhdmVkIGFuZCByZXBsYWNlZCBieSB0aGUgR1BJLWFuY2hvciwgYWxsb3dpbmcgdGhlIHByb3RlaW4gdG8gYmUgdGV0aGVyZWQgdG8gdGhlIGNlbGwgd2FsbC4KCkZvciBzaWduYWwgcGVwdGlkZSwgSSB1c2VkIHRoZSBbU2lnbmFsUCBzZXJ2ZXJdKGh0dHBzOi8vc2VydmljZXMuaGVhbHRodGVjaC5kdHUuZGsvc2VydmljZS5waHA/U2lnbmFsUCkuIEl0cyBsYXRlc3QgdmVyc2lvbiBpcyA2LjAuCgpgYGB7ciBzaWduYWxQLCBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD01fQojIFNpZ25hbCBwZXB0aWRlCmdmZi5uYW1lcyA8LSBjKCJuYW1lIiwgInNvdXJjZSIsICJ0eXBlIiwgInN0YXJ0IiwgImVuZCIsICJwcm9iIiwgIm5hMSIsICJuYTIiLCAibmEzIikKc2lnbmFscDYgPC0gcmVhZF90c3YoIi4uL291dHB1dC93ZWItZG93bmxvYWQvc2lnbmFscF82LjBfcmVzdWx0LmdmZjMiLCBjb21tZW50ID0gIiMiLCBjb2xfbmFtZXMgPSBnZmYubmFtZXMsIGNvbF90eXBlcyA9ICJjY2NpaWRjY2MiKQoKI2lmKCJzaWduYWxwIiAlaW4lIG5hbWVzKHNlcUluZm8pKQojICBzZXFJbmZvIDwtIHNlbGVjdChzZXFJbmZvLCAtc2lnbmFscCkKIwojc2VxSW5mbyA8LSBsZWZ0X2pvaW4oc2VxSW5mbywgc2VsZWN0KHNpZ25hbHA1LCBuYW1lID0gaWQsIHByb2IpLCBieSA9IGMoIm5hbWUiID0gIm5hbWUiKSkgJT4lIAojICBtdXRhdGUoc2lnbmFscCA9ICFpcy5uYShwcm9iKSkgJT4lIHNlbGVjdCgtcHJvYikKYGBgCgpGb3IgR1BJLWFuY2hvciBwcmVkaWN0aW9uLCBJIHVzZWQgdGhlIFtQcmVkR1BJIHNlcnZlcl0oaHR0cDovL2dwY3IuYmlvY29tcC51bmliby5pdC9wcmVkZ3BpLykuCmBgYHtyIGdwaX0KdG1wIDwtIHJlYWRfZGVsaW0oIi4uL291dHB1dC93ZWItZG93bmxvYWQvcHJlZGdwaS1yZXN1bHQtaGVhZGxpbmUtb25seS50eHQiLCBkZWxpbSA9ICJ8IiwgY29sX25hbWVzID0gYygibmFtZSIsImZwIiwib21lZ2EiKSkKcHJlZC5ncGkgPC0gdG1wICU+JSAKICBtdXRhdGUobmFtZSA9IHN0cl9zdWIobmFtZSwyLC0yKSwgIyByZW1vdmUgPiBhbmQgdGhlIHRyYWlsaW5nIHNwYWNlCiAgICAgICAgIGZwID0gYXMubnVtZXJpYyhzdHJfc3ViKGZwLCA5LCAtMikpLCAjIGV4dHJhY3QgdGhlIG51bWVyaWMgcGFydAogICAgICAgICBncGkucHJlZCA9IGZwIDw9IDAuMDEsICAgICMgYmFzZWQgb24gdGhlIGN1dG9mZiBvZiB0aGUgUHJlZEdQSSBzZXJ2ZXIgKHByb2IgPCA5OSUgLT4gbm90IEdQSS1hbmNob3JlZCkKICAgICAgICAgb21lZ2EgPSBzdHJfc3ViKG9tZWdhLCA4KSwKICAgICAgICAgY2xlYXZlUmVzID0gc3RyX3N1YihvbWVnYSwgMSwgMSksCiAgICAgICAgIGNsZWF2ZVBvcyA9IGFzLmludGVnZXIoc3RyX3N1YihvbWVnYSwgMykpCiAgICAgICAgICkKIyByZW1vdmUgdGhlIGNvbHVtbiBpZiBpdCBhbHJlYWR5IGV4aXN0cwojaWYoInByZWQuZ3BpIiAlaW4lIG5hbWVzKHNlcUluZm8pKQojICBzZXFJbmZvIDwtIHNlbGVjdChzZXFJbmZvLCAtcHJlZC5ncGkpCiNzZXFJbmZvIDwtIGxlZnRfam9pbihzZXFJbmZvLCBzZWxlY3QocHJlZC5ncGksIG5hbWUsIHByZWQuZ3BpID0gaXMuZ3BpKSwgYnkgPSBjKCJuYW1lIj0ibmFtZSIpKQpgYGAKCiMjIENvbWJpbmUgdGhlIE1MLCBTaWduYWxQIGFuZCBHUEktYW5jaG9yIHByZWRpY3Rpb25zCmBgYHtyfQphZGhlc2luIDwtIGJsYXN0SW5mbyAlPiUgCiAgc2VsZWN0KG5hbWUsIHNwZWNpZXMsIGxlbiA9IHNsZW4sIHBDb21wbGV0ZSkgJT4lIAogIGxlZnRfam9pbihmcnYsIGJ5ID0gIm5hbWUiKSAlPiUgCiAgbGVmdF9qb2luKHNpZ25hbHA2ICU+JSBzZWxlY3QobmFtZSwgc3AucHJvYiA9IHByb2IpLCBieSA9ICJuYW1lIikgJT4lIAogIGxlZnRfam9pbihwcmVkLmdwaSAlPiUgc2VsZWN0KG5hbWUsIGdwaS5wcmVkLCBjbGVhdmVQb3MpLCBieSA9ICJuYW1lIikgJT4lIAogIG11dGF0ZShzcC5wcmVkID0gIWlzLm5hKHNwLnByb2IpKSAlPiUgCiAgcmVsb2NhdGUoYyhmcnYucHJlZCwgc3AucHJlZCwgZ3BpLnByZWQpLCAuYWZ0ZXIgPSBwQ29tcGxldGUpCmBgYAoKRXhwb3J0IHRoZSBhZGhlc2luIHN1bW1hcnkgdGFibGUKYGBge3J9CndyaXRlX3RzdihhZGhlc2luLCBmaWxlID0gIi4uL291dHB1dC90YWJsZS8yMDIyMDgxOC1IaWwtZmFtaWx5LXNpemUtYWRoZXNpbi1zdGF0dXMtc3VtbWFyeS50c3YiKQpgYGAKClBsb3QgdGhlIHJlc3VsdHMgYWxvbmdzaWRlIHRoZSBzcGVjaWVzIHRyZWUuIEZpcnN0IGltcG9ydCB0aGUgc3BlY2llcyB0cmVlCmBgYHtyfQpzcHNJbmZvIDwtIHJlYWRfdHN2KCIuLi9kYXRhLzIwMjIwNTE4LWV4cGFuZGVkLWJsYXN0LXNwZWNpZXMtaW5mby50c3YiLCBjb2xfdHlwZXMgPSBjb2xzKCkpCnNwcy50cmVlIDwtIHJlYWQudHJlZSgiLi4vZGF0YS8yMDIyMDUyMS1nZW5lcmF4LXNwZWNpZXMtdHJlZS5ud2siKSAlPiUgCiAgYXNfdGliYmxlKCkgJT4lIAogIG11dGF0ZShsYWJlbCA9IGdzdWIoIl8iLCAiICIsIGxhYmVsKSkgJT4lIAogIGxlZnRfam9pbihzcHNJbmZvLCBieSA9IGMoImxhYmVsIiA9ICJzcGVjaWVzIikpICU+JSAKICBhcy50cmVlZGF0YSgpCiMgdG8gbGFiZWwgdGhlIGNsYWRlcwpjbGFkZSA8LSBjKAogIE1EUiA9IE1SQ0Eoc3BzLnRyZWUsICJDYW5kaWRhIGF1cmlzIiwgIkNhbmRpZGEgZHVvYnVzaGFlbXVsb25pcyIpLAogIENhTG8gPSBNUkNBKHNwcy50cmVlLCAiQ2FuZGlkYSBwYXJhcHNpbG9zaXMiLCAiQ2FuZGlkYSB0cm9waWNhbGlzIiksCiAgZ2xhYnJhdGEgPSBNUkNBKHNwcy50cmVlLCAiQ2FuZGlkYSBnbGFicmF0YSIsICJDYW5kaWRhIG5pdmFyaWVuc2lzIikKKQpzcHMudHJlZSA8LSBncm91cENsYWRlKHNwcy50cmVlLCBjbGFkZSkKYGBgCgpCZWNhdXNlIHdlIHdpbGwgcGxvdCB0aGUgcmVzdWx0cyBzZXBhcmF0ZWx5LCBpdCBpcyBpbXBvcnRhbnQgdG8gZ2VuZXJhdGUgdGhlIHNwZWNpZXMgdHJlZSBvYmplY3QgYW5kIGV4dHJhY3QgdGhlIG9yZGVyIG9mIHRoZSBzcGVjaWVzLCBzbyBhcyB0byBtYXRjaCB0aGUgbnVtYmVycyB0byB0aGUgc3BlY2llcy4KYGBge3J9CnAudHJlZSA8LSBnZ3RyZWUoc3BzLnRyZWUsIGxhZGRlcml6ZSA9IEZBTFNFKSArIHhsaW0oMCwyLjIpICsgc2NhbGVfeV9yZXZlcnNlKCkgKwogICNnZW9tX3RpcGxhYihhZXMoY29sb3IgPSBwYXRob2dlbiksIGFzX3lsYWIgPSBUUlVFKSArCiAgZ2VvbV90aXBsYWIoc2l6ZSA9IDMuMiwgZm9udGZhY2UgPSAiaXRhbGljIiwgYWxpZ24gPSBUUlVFLCBsaW5lc2l6ZSA9IDAuMSwgb2Zmc2V0ID0gMC4wNSkgKwogIGdlb21fdHJlZXNjYWxlKHggPSAwLCB3aWR0aCA9IDAuMiwgbGluZXNpemUgPSAxLjIpICsKICBnZW9tX2hpbGlnaHQobm9kZSA9IGNsYWRlWyJNRFIiXSwgZmlsbCA9ICIjN0YwMEZGIiwgYWxwaGEgPSAwLjE1KSAgKyAjIE1EUgogIGdlb21faGlsaWdodChub2RlID0gY2xhZGVbIkNhTG8iXSwgZmlsbCA9ICJwaW5rIiwgYWxwaGEgPSAwLjI1KSAgICArICMgQ2FuZGlkYS9Mb2RkZXJvbXljZXMKICBnZW9tX2hpbGlnaHQobm9kZSA9IGNsYWRlWyJnbGFicmF0YSJdLCBmaWxsID0gInN0ZWVsYmx1ZSIsIGFscGhhID0gMC4xNSkgICsgIyBnbGFicmF0YQogICNnZW9tX2NsYWRlbGFiZWwobm9kZSA9IGNsYWRlWyJNRFIiXSwgIGxhYmVsID0gIk1EUiIsIG9mZnNldCA9IDEuNSwjIGNvbG9yID0gInB1cnBsZSIsCiAgIyAgICAgICAgICAgICAgICBvZmZzZXQudGV4dCA9IDAuMDUsIGFuZ2xlID0gMjcwLCBoanVzdCA9IC41LCBleHRlbmQgPSAwLjUpICsjIE1EUgogICNnZW9tX2NsYWRlbGFiZWwobm9kZSA9IGNsYWRlWyJDYUxvIl0sICBsYWJlbCA9ICJDYW5kaWRhL1xuTG9kZGVyb215Y2VzIiwgb2Zmc2V0ID0gMS40NywjIGNvbG9yID0gImhvdHBpbmsyIiwKICAjICAgICAgICAgICAgICAgIG9mZnNldC50ZXh0ID0gMC4xLCBhbmdsZSA9IDI3MCwgaGp1c3QgPSAuNSwgZXh0ZW5kID0gMC41LCBmb250c2l6ZSA9IDMuNSkgKyAjIGFsYmljYW5zCiAgI2dlb21fY2xhZGVsYWJlbChub2RlID0gY2xhZGVbImdsYWJyYXRhIl0sICBsYWJlbCA9ICJnbGFicmF0YSIsIG9mZnNldCA9IDEuMzgsIyBjb2xvciA9ICJzdGVlbGJsdWUiLCAKICAjICAgICAgICAgICAgICAgIG9mZnNldC50ZXh0ID0gMC4wNSwgYW5nbGUgPSAyNzAsIGhqdXN0ID0gLjUsIGV4dGVuZCA9IDAuNSkgKyMgZ2xhYnJhdGEKICBnZW9tX3RpcHBvaW50KGFlcyhjb2xvciA9IHBhdGhvZ2VuKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSAgYygiY3J1c3RhY2VhbiIgPSAiIzZhNWFjZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJodW1hbiIgPSAiI2QxNDk0OSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiaHVtYW4gKHJhcmUpIiA9ICJzdGVlbGJsdWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibm8gcmVwb3J0IiA9ICJncmF5MjAiKSkgKwogICNndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQoYnlyb3cgPSBUUlVFKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC4xMiwgMC4xMykpCmBgYAoKU3VtbWFyaXplIHRoZSByZXN1bHRzCmBgYHtyfQpkZjAgPC0gYWRoZXNpbiAlPiUgCiAgbXV0YXRlKHNwZWNpZXMgPSBmYWN0b3Ioc3BlY2llcywgbGV2ZWxzID0gcmV2KGdldF90YXhhX25hbWUocC50cmVlKSkpKSAlPiUgCiAgZ3JvdXBfYnkoc3BlY2llcykgJT4lIAogIHN1bW1hcml6ZSh0b3RhbCA9IG4oKSwgRlJWID0gc3VtKGZydi5wcmVkKSwgU1AgPSBzdW0oc3AucHJlZCksIEdQSSA9IHN1bShncGkucHJlZCksIAogICAgICAgICAgICBmaW5hbCA9IHN1bShmcnYucHJlZCAmIHNwLnByZWQgJiBncGkucHJlZCkpICU+JSAKICBwaXZvdF9sb25nZXIodG90YWw6ZmluYWwsIG5hbWVzX3RvID0gInR5cGUiLCB2YWx1ZXNfdG8gPSAibnVtYmVyIikgJT4lIAogIG11dGF0ZSh0eXBlID0gZmFjdG9yKHR5cGUsIGxldmVscyA9IHVuaXF1ZSh0eXBlKSkpICU+JSAKICAjIGNvbXBsZXRlIG1pc3NpbmcgdmFsdWVzIGZvciBTLiBjZXJldmlzaWFlCiAgY29tcGxldGUoc3BlY2llcywgdHlwZSwgZmlsbCA9IGxpc3QobnVtYmVyID0gMCkpCgpwIDwtIGdncGxvdChkZjAsIGFlcyh4ID0gdHlwZSwgeSA9IHNwZWNpZXMpKSArIAogIHNjYWxlX3lfZGlzY3JldGUobGltaXRzID0gcmV2KSArCiAgZ2VvbV90aWxlKGFlcyhmaWxsID0gbnVtYmVyKSwgY29sb3IgPSAid2hpdGUiLCBhbHBoYSA9IDAuNCkgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBudW1iZXIpLCBjb2xvciA9ICJibGFjayIsIHNpemUgPSA0KSArCiAgc2NhbGVfZmlsbF9kaXN0aWxsZXIocGFsZXR0ZSA9ICJHcmV5cyIsIGRpcmVjdGlvbiA9IDEsIGxpbWl0cyA9IGMoMCwgMjApLCBvb2IgPSBzY2FsZXM6OnNxdWlzaCkgKwogIHNjYWxlX3hfZGlzY3JldGUocG9zaXRpb24gPSAidG9wIikgKwogIHRoZW1lX2Nvd3Bsb3QoKSArIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKZ2dzYXZlKHAsIGZpbGUgPSBwYXN0ZTAoIi4uL291dHB1dC9pbWcvIixnc3ViKCItIiwgIiIsIFN5cy5EYXRlKCkpLCAiLXNwZWNpZXMtYWRoZXNpbi1wcmVkaWN0aW9uLXN1bW1hcnkucG5nIiksIHdpZHRoID0gNSwgaGVpZ2h0ID0gNykKYGBgCmBgYHtyIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSA2fQpwMSA8LSBwICsgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSkKcGxvdF9ncmlkKHAudHJlZSwgcDEsIHJlbF93aWR0aHMgPSBjKDMsMiksIHNjYWxlID0gYygxLCAwLjk1KSkKYGBgClN1bW1hcml6ZSB0aGUgJSBvZiBIaWwgZ2VuZXMgcGFzc2luZyBhbGwgdGhyZWUgdGVzdHMKYGBge3J9CmRmMCAlPiUgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9ICJ0eXBlIiwgdmFsdWVzX2Zyb20gPSAibnVtYmVyIikgJT4lIAogIHNlbGVjdChzcGVjaWVzLCB0b3RhbCwgZmluYWwpICU+JSAKICBzdW1tYXJpemUodG90YWwgPSBzdW0odG90YWwpLCBhZGhlc2luID0gc3VtKGZpbmFsKSkKYGBgCgoKIyMgU2hvcnQgb3Igbm8gR1BJLWFuY2hvcgpBIHN1YnNldCBvZiB0aGUgaWRlbnRpZmllZCBIaWwgaG9tb2xvZ3MgYXJlIHNob3J0IGFuZC9vciBtaXNzaW5nIGVpdGhlciB0aGUgc2lnbmFsIHBlcHRpZGUgb3IgdGhlIEdQSSBhbmNob3IuIFdlIG5lZWQgdG8gZmlyc3QgZmlsdGVyIG91dCBvbmVzIHRoYXQgYXJlIGluY29tcGxldGUgKHNlcXVlbmNlIHJlY29yZCkgYmVmb3JlIGV4YW1pbmluZyB0aGUgcmVtYWluaW5nIG9uZXMuCgpGaXJzdCwgY2hlY2sgdGhlIHByb3RlaW4gbGVuZ3RoIGRpc3RyaWJ1dGlvbi4gX00uIGJpY3VzcGlkYXRhXyBpcyBhbiBvdXRsaWVyIGluIHRoYXQgMjcgb2YgdGhlIDI5IEhpbCBob21vbG9ncyBpbiB0aGlzIHNwZWNpZXMgYXJlIHNob3J0ZXIgdGhhbiA1MDAgYWEgYW5kIDEwIHdlcmUgYW5ub3RhdGVkIGFzIGJlaW5nIGluY29tcGxldGUgaW4gdGhlIFJlZlNlcSBkYXRhYmFzZS4KYGBge3J9CmFkaGVzaW4gJT4lIAogIG11dGF0ZShgTS4gYmljdXNwaWRhdGFgID0gc3BlY2llcyA9PSAiTWV0c2Nobmlrb3dpYSBiaWN1c3BpZGF0YSIsCiAgICAgICAgIHByb3RlaW4gPSBpZmVsc2UoZ3JlcGwoIm5vIiwgcENvbXBsZXRlKSwgIkluY29tcGxldGUiLCAiQ29tcGxldGUiKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IGxlbiwgZmlsbCA9IGBNLiBiaWN1c3BpZGF0YWApKSArIAogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMTAwKSArIAogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDYwMCwgbGluZXR5cGUgPSAyLCBjb2xvciA9ICJncmF5MjAiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiZ3JheTUwIiwgInJlZDMiKSkgKwogIGZhY2V0X3dyYXAofnByb3RlaW4sIG5yb3cgPSAyLCBsYWJlbGxlciA9ICJsYWJlbF9ib3RoIikgKwogIHhsYWIoIlByb3RlaW4gbGVuZ3RoIikgKyB5bGFiKCJGcmVxdWVuY3kiKSArCiAgdGhlbWVfY293cGxvdCgpICsgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAzKSkKZ2dzYXZlKGZpbGUgPSAiLi4vb3V0cHV0L2ltZy8yMDIyMTAwMi1ob21vbG9ncy1sZW5ndGgtZGlzdHJpYnV0aW9uLU1iLnBuZyIsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNCkKYGBgCgpGaWx0ZXIgb3V0IGluY29tcGxldGUgZW50cmllcyBhbmQgZm9jdXMgb24gdGhvc2UgdGhhdCBlaXRoZXIgYXJlIHNob3J0IG9yIG1pc3MgU1AvR1BJCmBgYHtyfQojIHNob3J0IGFuZCBtaXNzaW5nIFNQL0dQSQphZGhlc2luICU+JSAKICBmaWx0ZXIoIWdyZXBsKCJubyIsIHBDb21wbGV0ZSksIGxlbiA8IDYwMCwgbGVuID4gMjUwKSAlPiUgCiAgZ3JvdXBfYnkoc3AucHJlZCwgZ3BpLnByZWQsIHNwZWNpZXMpICU+JSAKICBzdW1tYXJpemUobiA9IG4oKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lIAogIG11dGF0ZShncm91cCA9IHBhc3RlMChpZmVsc2Uoc3AucHJlZCwgIlNQKyIsICJzcC0iKSwgaWZlbHNlKGdwaS5wcmVkLCAiR1BJKyIsICJncGktIikpKSAlPiUgCiAgc2VsZWN0KGdyb3VwLCBzcGVjaWVzLCBuKSAlPiUgCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGdyb3VwLCB2YWx1ZXNfZnJvbSA9IG4sIHZhbHVlc19maWxsID0gMCkgJT4lIAogIG11dGF0ZSh0b3RhbCA9IHJvd1N1bXMoYWNyb3NzKGBzcC1ncGktYDpgU1ArR1BJK2ApLCBuYS5ybSA9IFRSVUUpKSAlPiUgCiAgYXJyYW5nZShkZXNjKHRvdGFsKSkgJT4lIAogIHdyaXRlX3RzdihmaWxlID0gIi4uL291dHB1dC90YWJsZS8yMDIyMTAwMy1zaG9ydC1hbmQtbWlzc2luZy1TUC1HUEkudHN2IikKCiMgbG9uZyBhbmQgbWlzc2luZyBTUC9HUEkKYWRoZXNpbiAlPiUgCiAgZmlsdGVyKCFncmVwbCgibm8iLCBwQ29tcGxldGUpLCBsZW4gPj0gNjAwKSAlPiUgCiAgZ3JvdXBfYnkoc3AucHJlZCwgZ3BpLnByZWQsIHNwZWNpZXMpICU+JSAKICBzdW1tYXJpemUobiA9IG4oKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lIAogIG11dGF0ZShncm91cCA9IHBhc3RlMChpZmVsc2Uoc3AucHJlZCwgIlNQKyIsICJzcC0iKSwgaWZlbHNlKGdwaS5wcmVkLCAiR1BJKyIsICJncGktIikpKSAlPiUgCiAgc2VsZWN0KGdyb3VwLCBzcGVjaWVzLCBuKSAlPiUgCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGdyb3VwLCB2YWx1ZXNfZnJvbSA9IG4sIHZhbHVlc19maWxsID0gMCkgJT4lIAogIG11dGF0ZSh0b3RhbCA9IHJvd1N1bXMoYWNyb3NzKGBzcC1ncGktYDpgU1ArR1BJK2ApLCBuYS5ybSA9IFRSVUUpKSAlPiUgCiAgYXJyYW5nZShkZXNjKHRvdGFsKSkgJT4lIAogIHdyaXRlX3RzdihmaWxlID0gIi4uL291dHB1dC90YWJsZS8yMDIyMTAwMy1sb25nLWFuZC1taXNzaW5nLVNQLUdQSS50c3YiKQoKIyBhbGwgbGVuZ3RoCmFkaGVzaW4gJT4lIAogIGZpbHRlcighZ3JlcGwoIm5vIiwgcENvbXBsZXRlKSkgJT4lIAogIG11dGF0ZShsZW5ndGggPSBjdXQobGVuLCBicmVha3MgPSBjKDAsIDI1MCwgNjAwLCA1MDAwKSwgbGFiZWxzID0gYygiMC0yNTAiLCAiMjUxLTYwMCIsICI+NjAwIikpKSAlPiUgCiAgZ3JvdXBfYnkoc3AucHJlZCwgZ3BpLnByZWQsIGxlbmd0aCkgJT4lIAogIHN1bW1hcml6ZShuID0gbigpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUgCiAgbXV0YXRlKGdyb3VwID0gcGFzdGUwKGlmZWxzZShzcC5wcmVkLCAiU1ArIiwgInNwLSIpLCBpZmVsc2UoZ3BpLnByZWQsICJHUEkrIiwgImdwaS0iKSkpICU+JSAKICBzZWxlY3QoZ3JvdXAsIGxlbmd0aCwgbikgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBncm91cCwgdmFsdWVzX2Zyb20gPSBuLCB2YWx1ZXNfZmlsbCA9IDApICU+JSAKICBtdXRhdGUodG90YWwgPSByb3dTdW1zKGFjcm9zcyhgc3AtZ3BpLWA6YFNQK0dQSStgKSwgbmEucm0gPSBUUlVFKSkgJT4lIAogIGFycmFuZ2UoZGVzYyh0b3RhbCkpICU+JSAKICB3cml0ZV90c3YoZmlsZSA9ICIuLi9vdXRwdXQvdGFibGUvMjAyMjEwMDMtYWxsLW1pc3NpbmctU1AtR1BJLnRzdiIpCiAgCmBgYAoKIyBBZGhlc2luLXJlbGF0ZWQgY2hhcmFjdGVyaXN0aWNzCgoqKlVwZGF0ZSAyMDIyLTA5LTE2KioKClJlbW92ZSBfTS4gYmljdXNwaWRhdGFfIHNlcXVlbmNlcyBmcm9tIGNvbnNpZGVyYXRpb24sIGR1ZSB0byBhIGxhcmdlIG51bWJlciBvZiB0aGVtIGJlaW5nIGluY29tcGxldGUgYW5kIHBvc3NpYmx5IHNrZXdpbmcgdGhlIHJlc3VsdHMuCgpgYGB7cn0KTWIucm0gPC0gYmxhc3RJbmZvICU+JSAKICBmaWx0ZXIoc3BlY2llcyA9PSAiTWV0c2Nobmlrb3dpYSBiaWN1c3BpZGF0YSIpICU+JSAKICBzZWxlY3QocGlkLCBuYW1lKQpgYGAKCiMjIFNlcmluZS9UaHJlb25pbmUgY29udGVudAoKUy9UIHNpdGVzIGFyZSBwb3RlbnRpYWwgc2l0ZXMgZm9yIE8tZ2x5Y29zeWxhdGlvbiwgd2hpY2ggY291bGQgaW5jcmVhc2UgdGhlIHJpZGlkaXR5IG9mIHRoZSBzdGFsayBvZiB0aGUgcHJvdGVpbiBhbmQgYWxsb3cgdGhlIE4tdGVybWluYWwgZG9tYWluIHRvIHByb3RydWRlIG91dCBvZiB0aGUgY2VsbCB3YWxsIGZhY2luZyB0aGUgZXh0ZXJpb3IuIE1vcmUgZXZpZGVuY2UgZm9yIHRoZSBpbXBvcnRhbmNlIG9mIE8tZ2x5Y29zeWxhdGlvbiBpbiBhIHNlcmluZS90aHJlb25pbmUtcmljaCBkb21haW4gY2FuIGJlIGZvdW5kIFtoZXJlXShodHRwczovL2VjLmFzbS5vcmcvY29udGVudC8xMC8xMC8xMzE3LmxvbmcpLgoKVGhlIGdvYWwgaGVyZSBpcyB0byBjb21wYXJlIHRoZSBTL1QgZnJlcXVlbmNpZXMgaW4gdGhlIEhpbCBwcm90ZWlucyB0byB0aGUgcHJvdGVvbWUgYXZlcmFnZS4gRmlyc3Qgd2UgbmVlZCB0byBjYWxjdWxhdGUgdGhlIFMvVCBmcmVxdWVuY2llcyBpbiB0aGUgSGlsIHByb3RlaW5zLCBlaXRoZXIgaW4gdGhlIHdob2xlIHByb3RlaW4gb3IgZXhjbHVkaW5nIHRoZSBQRjExNzY1IGRvbWFpbi4gVGhpcyBpcyBkb25lIHdpdGggYSBzY3JpcHQgaW4gdGhlIGBzY3JpcHRgIGZvbGRlciBuYW1lZCBgSGlsLVNULWZyZXEuc2hgCgpSZWFkIGluIHRoZSBTL1QgZnJlcXVlbmNpZXMKYGBge3J9ClNUIDwtIGxpc3QoCiAgZnVsbCA9IHJlYWRfdHN2KCIuLi9vdXRwdXQvU1QtZnJlcS8yMDIyMDYyMy1IaWwtZnVsbC1TVGZyZXEub3V0Lmd6IiwgY29sX3R5cGVzID0gImNpaWkiKSwKICBub05URCA9IHJlYWRfdHN2KCIuLi9vdXRwdXQvU1QtZnJlcS8yMDIyMDYyMy1IaWwtbm9QRjExNzY1LVNUZnJlcS5vdXQuZ3oiLCBjb2xfdHlwZXMgPSAiY2lpaSIpCikKYGBgCgpUbyBkZXRlcm1pbmUgdGhlIGJhY2tncm91bmQgZnJlcXVlbmN5IG9mIFNlcmluZSBhbmQgVGhyZW9uaW5lIGluIHRoZSBwcm90ZW9tZShzKSwgSSBtb2RpZmllZCB0aGUgYGNhbGNfYWFmcmVxX2d6LnB5YCBzY3JpcHQgSSB3cm90ZSBhIGxvbmcgdGltZSBhZ28gZm9yIGNhbGN1bGF0aW5nIHRoZSBjeXN0ZWluIGFuZCBkaWJhc2ljIHJlc2lkdWVzLiBJIHRoZW4gY29waWVkIGZvdXIgcHJvdGVvbWUgZmFzdGEgZmlsZXMsIGZvciBfQy4gYWxiaWNhbnNfLCBfQy4gZ2xhYnJhdGFfLCBfUy4gY2VyZXZpc2lhZV8gYW5kIF9DLiBhdXJpc18gYW5kIGFwcGxpZWQgdGhlIHNjcmlwdCBvbiB0aGVtICh1c2luZyBhIHdyYXBwZXIgc2NyaXB0IGNhbGxlZCBgUy1ULWZyZXEuc2hgKS4gQmVsb3cgSSB3aWxsIGxvb2sgYXQgYm90aCB0aGUgcHJvdGVvbWUgYXZlcmFnZSBhbmQgdGhlIGRpc3RyaWJ1dGlvbiBvZiBTL1QgaW4gaW5kaXZpZHVhbCBwcm90ZWlucyBhY3Jvc3MgdGhlIHByb3Rlb21lLgpgYGB7cn0KdG1wLmZpbGVzIDwtIGxpc3QuZmlsZXMocGF0aCA9ICIuLi9vdXRwdXQvU1QtZnJlcS8iLCBwYXR0ZXJuID0gIipTVC1mcmVxLnRzdi5neiIpCmZpbGVzIDwtIGZpbGUucGF0aCgiLi4vb3V0cHV0L1NULWZyZXEiLCB0bXAuZmlsZXMpCm5hbWVzKGZpbGVzKSA8LSBnc3ViKCItIiwgIiAiLCB0bXAuZmlsZXMpICU+JSB3b3JkKDEsIDEpCmJnU1QuZnJlcSA8LSBmaWxlcyAlPiUgCiAgbWFwKH5yZWFkX3RzdiguLCBjb2xfdHlwZXMgPSBjb2xzKCkpKSAlPiUgCiAgYmluZF9yb3dzKC5pZCA9ICJTcGVjaWVzIikgJT4lIAogIG11dGF0ZShmcmVxUyA9IFNlci9sZW5ndGgsIGZyZXFUID0gVGhyL2xlbmd0aCwKICAgICAgICAgU2VyID0gTlVMTCwgVGhyID0gTlVMTCwKICAgICAgICAgU3BlY2llcyA9IHBhc3RlMChzdHJfc3ViKFNwZWNpZXMsIDEsIDEpLCAiLiAiLCBzdHJfc3ViKFNwZWNpZXMsIDIpKSkgJT4lIAogIHBpdm90X2xvbmdlcihjb2xzID0gc3RhcnRzX3dpdGgoImZyZXEiKSwgbmFtZXNfdG8gPSAiUmVzaWR1ZSIsIG5hbWVzX3ByZWZpeCA9ICJmcmVxIiwgdmFsdWVzX3RvID0gImZyZXF1ZW5jeSIpCmBgYAoKSXMgdGhlcmUgYW55IGNvcnJlbGF0aW9ucyBiZXR3ZWVuIHByb3RlaW4gbGVuZ3RoIGFuZCBTL1QgZnJlcXVlbmN5PwpgYGB7cn0KYmdTVC5mcmVxICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBsZW5ndGgsIHkgPSBmcmVxdWVuY3kpKSArCiAgZ2VvbV9oZXgoKSArIGZhY2V0X2dyaWQoUmVzaWR1ZSB+IFNwZWNpZXMsIHNjYWxlcyA9ICJmcmVlX3kiKSArIAogIHNjYWxlX3hfbG9nMTAoKSArIHhsYWIoIlByb3RlaW4gbGVuZ3RoIikKYGBgCkRvZXNuJ3Qgc2VlbSB0byBiZSBzaWduaWZpY2FudC4KCk5vdyBsZXQncyBjb21iaW5lIHRoZSBIaWwgcHJvdGVpbiBTL1QgZnJlcXVlbmNlcyBhcyBhbiBleHRyYSAic3BlY2llcyIgaW50byB0aGUgYGJnU1QuZnJlcWAKYGBge3J9CnRtcCA8LSBTVCRmdWxsICU+JSAKICBmaWx0ZXIoIUlEICVpbiUgTWIucm0kbmFtZSkgJT4lIAogIG11dGF0ZShTcGVjaWVzID0gIkhpbCBmYW1pbHkiLCBgU2AgPSBTZXIvbGVuZ3RoLCBgVGAgPSBUaHIvbGVuZ3RoKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKGBTYCwgYFRgKSwgbmFtZXNfdG8gPSAiUmVzaWR1ZSIsIHZhbHVlc190byA9ICJmcmVxdWVuY3kiKSAlPiUgCiAgc2VsZWN0KFNwZWNpZXMsIElELCBsZW5ndGgsIFJlc2lkdWUsIGZyZXF1ZW5jeSkgJT4lIAogIGJpbmRfcm93cyhmaWx0ZXIoYmdTVC5mcmVxLCBTcGVjaWVzICE9ICJTLiBjZXJldmlzaWFlIikpICU+JSAKICBtdXRhdGUoUmVzaWR1ZSA9IGZhY3RvcihSZXNpZHVlLCBsZXZlbHMgPSBjKCJTIiwgIlQiKSwgbGFiZWxzID0gYygiU2VyIiwgIlRociIpKSkKI3RtcCA8LSBTVCRub05URCAlPiUgCiMgIG11dGF0ZShTcGVjaWVzID0gIkhpbC1QRjExNzY1IiwgUyA9IFNlci9sZW5ndGgsIGBUYCA9IFRoci9sZW5ndGgpICU+JSAKIyAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKFMsIGBUYCksIG5hbWVzX3RvID0gIlJlc2lkdWUiLCB2YWx1ZXNfdG8gPSAiZnJlcXVlbmN5IikgJT4lIAojICBzZWxlY3QoU3BlY2llcywgSUQsIGxlbmd0aCwgUmVzaWR1ZSwgZnJlcXVlbmN5KSAlPiUKIyAgYmluZF9yb3dzKHRtcCkKCnAgPC0gdG1wICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBTcGVjaWVzLCB5ID0gZnJlcXVlbmN5LCBmaWxsID0gUmVzaWR1ZSkpICsgCiAgZ2VvbV9ib3hwbG90KHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC45KSwgb3V0bGllci5zaXplID0gMC4yLCBvdXRsaWVyLmFscGhhID0gMC41KSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIlRociIgPSAic2t5Ymx1ZTMiLCAiU2VyIiA9ICJsaWdodGJsdWUxIikpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAwLjQpLCBvb2IgPSBzY2FsZXM6OnNxdWlzaCkgKwogIHRoZW1lX2Nvd3Bsb3QoKSArIHBhbmVsX2JvcmRlcihjb2xvciA9ICJibGFjayIpICsKICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAzKSkKCnAjICsgcDEgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiUyIgPSBhbHBoYSgiZ3JheTIwIiwgMC41KSwgIlQiID0gYWxwaGEoImdyYXkyMCIsIDAuNSkpKQpnZ3NhdmUoIi4uL291dHB1dC9pbWcvMjAyMjA2MjMtSGlsLVNULWZyZXEtY29tcGFyZWQtdG8tcHJvdGVvbWUucG5nIiwgd2lkdGggPSA1LCBoZWlnaHQgPSAyLjUpCmBgYAoKCmBgYHtyfQpiZ1NULmZyZXEgJT4lIAogIGdyb3VwX2J5KFNwZWNpZXMsIFJlc2lkdWUpICU+JSAKICBzdW1tYXJpemUobWVhbiA9IHJvdW5kKG1lYW4oZnJlcXVlbmN5KSwzKSkgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBSZXNpZHVlLCB2YWx1ZXNfZnJvbSA9IG1lYW4pCmBgYAoKPCEtLSAjIyMgU2xpZGluZyB3aW5kb3cgZXN0aW1hdGVzIC0tPgo8IS0tIFRvIGRldGVybWluZSB0aGUgUy9UIGZyZXF1ZW5jeSBpbiB0aGUgWFBfMDI4ODg5MDMzIGhvbW9sb2dzLCBJIHJhbiB0aGUgcHJvZ3JhbSBgZnJlYWtgIGZyb20gdGhlIEVNQk9TUyBzdWl0ZSB3aXRoIHRoZSBwYXJhbWV0ZXJzIG9mIDEwMCBhYSBzbGlkaW5nIHdpbmRvdyBhbmQgYSBzdGVwIHNpemUgb2YgMTAgYWEuIEFmdGVyIHJlZm9ybWF0aW5nIHRoZSBvdXRwdXQsIHRoZSByZXN0IG9mIHRoZSBhbmFseXNpcyBpcyBhY2NvbXBsaXNoZWQgYmVsb3cuIC0tPgoKCjwhLS0gYGBge3IgU19UX2ZyZXF9IC0tPgo8IS0tICMgbG9hZCBkYXRhIC0tPgo8IS0tIFNULmZyZXEgPC0gcmVhZF90c3YoIm91dHB1dC9TVC1mcmVxL1NUX2ZyZXFfMTAwXzEwX2ZyZWFrLm91dC5neiIsIGNvbF90eXBlcyA9ICJjaWQiKSAtLT4KPCEtLSBTLmZyZXEgPC0gcmVhZF90c3YoIm91dHB1dC9TVC1mcmVxL1NfZnJlcV8xMDBfMTBfZnJlYWsub3V0Lmd6IiwgY29sX3R5cGVzID0gImNpZCIpIC0tPgo8IS0tIFQuZnJlcSA8LSByZWFkX3Rzdigib3V0cHV0L1NULWZyZXEvVF9mcmVxXzEwMF8xMF9mcmVhay5vdXQuZ3oiLCBjb2xfdHlwZXMgPSAiY2lkIikgLS0+CjwhLS0gIyBjb252ZXJ0IHNlcXVlbmNlIG5hbWUgY29sdW1uIHRvIGFuIG9yZGVyZWQgbGlzdCBzb3J0ZWQgYmFzZWQgb24gdGhlIGdlbmUgdHJlZSBzZXF1ZW5jZSAtLT4KPCEtLSBTVC5mcmVxIDwtIFNULmZyZXEgJT4lICBtdXRhdGUoaWQgPSBvcmRlcmVkKGlkLCBsZXZlbHMgPSByZXYoZ2VuZXRyZWVPcmRlcikpKSAjIHRoaXMgd2lsbCBwcm9kdWNlIHRoZSBkZXNpcmVkIG9yZGVyIC0tPgo8IS0tIFMuZnJlcSA8LSBTLmZyZXEgJT4lICBtdXRhdGUoaWQgPSBvcmRlcmVkKGlkLCBsZXZlbHMgPSByZXYoZ2VuZXRyZWVPcmRlcikpKSAjIHRoaXMgd2lsbCBwcm9kdWNlIHRoZSBkZXNpcmVkIG9yZGVyIC0tPgo8IS0tIFQuZnJlcSA8LSBULmZyZXEgJT4lICBtdXRhdGUoaWQgPSBvcmRlcmVkKGlkLCBsZXZlbHMgPSByZXYoZ2VuZXRyZWVPcmRlcikpKSAjIHRoaXMgd2lsbCBwcm9kdWNlIHRoZSBkZXNpcmVkIG9yZGVyIC0tPgo8IS0tIGBgYCAtLT4KCjwhLS0gYGBge3IgcGxvdF9TVF9mcmVxLCBmaWcud2lkdGggPSA2LCBmaWcuaGVpZ2h0PTZ9IC0tPgo8IS0tIGdncGxvdChTVC5mcmVxLCBhZXMoeCA9IGlkLCB5ID0gcG9zKSkgKyAgZ2VvbV90aWxlKGFlcyhmaWxsID0gZnJlcSkpICsgLS0+CjwhLS0gICBjb29yZF9mbGlwKCkgKyB0aGVtZV9jbGFzc2ljKCkgKyBzY2FsZV9maWxsX2Rpc3RpbGxlcihwYWxldHRlID0gIlJkR3kiLCBsaW1pdHMgPSBjKDAsIDAuOCksIG9vYiA9IHNjYWxlczo6c3F1aXNoLCBicmVha3MgPSBzZXEoMCwgMC42LCBieSA9IDAuMikpICsgLS0+CjwhLS0gICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNSksIC0tPgo8IS0tICAgICAgICAgYXhpcy5saW5lLnkgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwgLS0+CjwhLS0gICAgICAgICBheGlzLmxpbmUueCA9IGVsZW1lbnRfYmxhbmsoKSwjIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwgLS0+CjwhLS0gICAgICAgICBsZWdlbmQucG9zaXRpb24gPSBjKDAuODUsMC4zNSksIC0tPgo8IS0tICAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gYWxwaGEoImxpZ2h0Ymx1ZSIsMC41KSkpICsgLS0+CjwhLS0gICB5bGltKDEsIDQ1MDApICsgbGFicyh5ID0gIlBvc2l0aW9uIGluIHNlcXVlbmNlIiwgeCA9ICJTZXF1ZW5jZXMiLCBjb2xvciA9ICJGcmVxdWVuY3kiKSArICAtLT4KPCEtLSAgIGdndGl0bGUoIlNlcmluZS9UaHJlb25pbmUgZnJlcXVlbmN5IGluIDEwMCBhYSBzbGlkaW5nIHdpbmRvd3MiKSAtLT4KPCEtLSBnZ3NhdmUoIm91dHB1dC9pbWcvMjAyMDEyMjMtaG9tb2xvZ3MtU1QtZnJlcS0xMDBhYS13aW5kb3cucG5nIiwgYmcgPSAidHJhbnNwYXJlbnQiLCB3aWR0aCA9IDcsIGhlaWdodCA9IDcpIC0tPgo8IS0tIGBgYCAtLT4KPCEtLSBgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Ny41fSAtLT4KPCEtLSBTVC5jb21iIDwtIGJpbmRfcm93cyhTZXIgPSBTLmZyZXEsIFRociA9IFQuZnJlcSwgLmlkID0gIlZhciIpICU+JSAgLS0+CjwhLS0gICBtdXRhdGUoVmFyID0gb3JkZXJlZChWYXIsIGxldmVscyA9IGMoIlNlciIsIlRociIpKSkgLS0+CjwhLS0gcC5zdCA8LSBnZ3Bsb3QoU1QuY29tYiwgYWVzKHggPSBpZCwgeSA9IHBvcykpICsgZ2VvbV90aWxlKGFlcyhmaWxsID0gZnJlcSksIHNpemUgPSAyKSArICAtLT4KPCEtLSAgIGZhY2V0X3dyYXAoflZhciwgc2NhbGVzID0gImZpeGVkIikgKyB0aGVtZV9jbGFzc2ljKCkgKyAtLT4KPCEtLSAgIGNvb3JkX2ZsaXAoKSArICAtLT4KPCEtLSAgICNzY2FsZV9maWxsX2Rpc3RpbGxlcihwYWxldHRlID0gIlJkR3kiLCBsaW1pdHMgPSBjKC0wLjEsIDAuNzUpLCBvb2IgPSBzY2FsZXM6OnNxdWlzaCwgYnJlYWtzID0gc2VxKDAsMC43LGJ5PTAuMSkpICsgLS0+CjwhLS0gICBzY2FsZV9maWxsX2dyYWRpZW50Mihsb3cgPSAiZ3JheTEwIiwgaGlnaCA9ICIjMDA2MDAwIiwgbWlkID0gImdyYXk5MCIsIG1pZHBvaW50ID0gMC4wNSwgYnJlYWtzID0gc2VxKDAsMC43LGJ5PTAuMSkpICsgLS0+CjwhLS0gICAjc2NhbGVfZmlsbF9zdGVwczIobG93ID0gIiMwMDAwMDAiLCBoaWdoID0gIiNiMzAwMDAiLCBtaWRwb2ludCA9IDAuMSwgYnJlYWtzID0gc2VxKDAsMC43LGJ5PTAuMSkpICsgLS0+CjwhLS0gICAjc2NhbGVfZmlsbF92aXJpZGlzX2Iobi5icmVha3MgPSAxMCwgYmVnaW4gPSAwLjEpICsgLS0+CjwhLS0gICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNCksIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwgLS0+CjwhLS0gICAgICAgICBheGlzLmxpbmUueSA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLCAtLT4KPCEtLSAgICAgICAgIGF4aXMubGluZS54ID0gZWxlbWVudF9ibGFuaygpLCMgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLCAtLT4KPCEtLSAgICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksIC0tPgo8IS0tICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gYygwLjkyLDAuNDApLCAtLT4KPCEtLSAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9IGFscGhhKCJsaWdodGJsdWUiLDAuNSkpKSArIC0tPgo8IS0tICAgeWxpbSgxLCA0NTAwKSArIHlsYWIoIlBvc2l0aW9uIGluIHNlcXVlbmNlIikgKyB4bGFiKCJTZXF1ZW5jZXMiKSAgLS0+CjwhLS0gI3Bsb3RfZ3JpZChwLmd0cmVlLCBwLnN0LCBuY29sID0gMiwgYWxpZ24gPSAndicsIHJlbF93aWR0aHMgPSBjKDEsMyksIHNjYWxlID0gYygwLjk5LDEpKSAtLT4KPCEtLSBwLnN0IC0tPgo8IS0tIGdnc2F2ZSgib3V0cHV0L2ltZy8yMDIwMTIyMy1TVC1mcmVxLWNvbXBvc2l0ZS5wbmciLCB3aWR0aCA9IDcsIGhlaWdodCA9IDcuNSkgLS0+CjwhLS0gYGBgIC0tPgoKIyMgVGFuZGVtIHJlcGVhdHMKVGhlIG5vbi1OVEQgcG9ydGlvbiBvZiB0aGUgcHJvdGVpbnMgZXZvbHZlIHJhcGlkbHkgYW5kIG1hbnkgb2YgdGhlbSBjb250YWluIHRhbmRlbSByZXBlYXRzLiBUaGVyZWZvcmUsIGNoYXJhY3Rlcml6aW5nIGFuZCB2aXN1YWxpemluZyB0aGUgdHlwZSwgbnVtYmVyIGFuZCBzcGF0aWFsIGRpc3RyaWJ1dGlvbiBvZiB0aGUgdGFuZGVtIHJlcGVhdHMgc2VydmUgdG8gaGlnaGxpZ2h0IHRoZSBkaWZmZXJlbmNlcyBpbiB0aGUgbm9uLU5URCBwYXJ0IG9mIHRoZSBwcm90ZWlucyBpbiB0aGlzIGZhbWlseS4KClRvIGlkZW50aWZ5IGFuZCBncm91cCB0YW5kZW0gcmVwZWF0cywgSSB1c2VkIFtYU1RSRUFNXShodHRwczovL2FtbmV3bWFubGFiLnN0YW5mb3JkLmVkdS94c3RyZWFtKSB3aXRoIHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVycyBgamF2YSAtWG14MTAwMG0gLVhtczEwMDBtIC1qYXIgfi9zdy9YU1RSRUFNL3hzdHJlYW0uamFyICRpbiAtaS43IC1JLjcgLWczIC1lMiAtTDE1IC16IC1CIC1PIC1Bc3ViLnR4dGAuIFRoZSBwYXJhbWV0ZXJzIHdlcmUgY2hvc2VuIHRvIGlkZW50aWZ5IGRlZ2VuZXJhdGUgdGFuZGVtIHJlcGVhdHMgdGhhdCBvY2N1ciBhdCBsZWFzdCB0d28gdGltZXMgYW5kIHRoZSBtaW5pbXVtIGxlbmd0aCBvZiBhIHRhbmRlbSByZXBlYXQgZG9tYWluICg9cGVyaW9kIHggY29weSAjKSBtdXN0IGJlIGdyZWF0ZXIgdGhhbiAxNSBhLmEuIFBsZWFzZSBzZWUgYHNjcmlwdC94c3RyZWFtLnNoYCBmb3IgZXhwbGFuYXRpb24gb2YgdGhlIHBhcmFtZXRlcnMuCgpgYGB7cn0KdGFuZGVtIDwtIHJlYWRfdHN2KCIuLi9vdXRwdXQveHN0cmVhbS9YU1RSRUFNX3N1Yl9pMC43X2czX201X0wxNV9jaGFydC50c3YiLAogICAgICAgICAgICAgICAgICAgY29sX3R5cGVzID0gImNpaWlmaWRjY2NkIiwgY29tbWVudCA9ICIjIikKIyBub3cgbGV0J3MgY3JlYXRlIGEgdGliYmxlIGZvciBwbG90dGluZywgd2hpY2ggd291bGQgY29udGFpbiBlYWNoIGluc3RhbmNlIG9mIHRoZSB0YW5kZW0gcmVwZWF0IG9uIGEgc2VwYXJhdGUgcm93CnRhbmRlbS5kaXYgPC0gdGFuZGVtICU+JSAKICByb3d3aXNlKG5hbWUpICU+JSAKICBzdW1tYXJpemUoZGl2ID0gbGlzdChjKHNlcShmcm9tID0gc3RhcnQsIHRvID0gZW5kLCBieSA9IHBlcmlvZCksIGVuZCkpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUgCiAgdW5uZXN0KGRpdikKYGBgCgpFeGFtaW5lIHRoZSBkaXN0cmlidXRpb24gb2YgdGFuZGVtIHJlcGVhdCBsZW5ndGggYXMgYSBmcmFjdGlvbiBvZiB0aGUgdG90YWwgcHJvdGVpbiBtaW51cyB0aGUgUEYxMTc2NSBkb21haW4KYGBge3J9CiMgY2FsY3VsYXRlIHRoZSBsZW5ndGggb2YgdGhlIFBGMTE3NjUgZG9tYWluIGluIGVhY2ggcHJvdGVpbgpwZjExNzY1IDwtIHJlYWRfdHN2KCIuLi9kYXRhLzIwMjIwNjIzLWV4cGFuZGVkLWJsYXN0LWNvbWJpbmVkLWhvbW9sb2dzLVBGMTE3NjUtbG9uZ25hbWUuQkVEIiwgCiAgICAgICAgICAgICAgICAgICAgY29sX25hbWVzID0gYygibmFtZSIsICJzdGFydCIsICJlbmQiKSwgY29sX3R5cGVzID0gY29scygpKQoKcGYxMTc2NS5sZW4gPC0gcGYxMTc2NSAlPiUgCiAgbXV0YXRlKGxlbiA9IGVuZCAtIHN0YXJ0KSAlPiUgCiAgZ3JvdXBfYnkobmFtZSkgJT4lIAogIHN1bW1hcml6ZShkbUxlbiA9IHN1bShsZW4pLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUgCiAgYXJyYW5nZShkZXNjKGRtTGVuKSkKCiMgY2FsY3VsYXRlIHJlcGVhdCBjb250ZW50CnRyLmxlbiA8LSB0YW5kZW0gJT4lIAogIG11dGF0ZSh0ckxlbmd0aCA9IGVuZCAtIHN0YXJ0ICsgMSkgJT4lIAogIGdyb3VwX2J5KG5hbWUpICU+JSAKICBzdW1tYXJpemUodHJMZW4gPSBzdW0odHJMZW5ndGgpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUgCiAgcmlnaHRfam9pbihzZWxlY3QoYmxhc3RJbmZvLCBuYW1lLCBzZXFMZW4gPSBzbGVuLCBzcGVjaWVzKSwKICAgICAgICAgICAgIGJ5ID0gIm5hbWUiKSAlPiUgCiAgbXV0YXRlKHRyTGVuID0gaWZlbHNlKGlzLm5hKHRyTGVuKSwgMCwgdHJMZW4pKSAlPiUgCiAgZnVsbF9qb2luKHBmMTE3NjUubGVuLCBieSA9ICJuYW1lIikgJT4lCiAgbXV0YXRlKG5vbk5URExlbiA9IHNlcUxlbiAtIGRtTGVuLCB0ci5wZXJjID0gdHJMZW4vbm9uTlRETGVuKSAlPiUgCiAgZnVsbF9qb2luKHNlbGVjdChhZGhlc2luLCBuYW1lLCBmcnYucHJlZCwgc3AucHJlZCwgZ3BpLnByZWQpLCBieSA9ICJuYW1lIikgJT4lIAogIHJlbG9jYXRlKHNwZWNpZXMsIC5hZnRlciA9IGxhc3RfY29sKCkpCgojIHJlbW92ZSBNLiBiaWN1c3BpZGF0YQp0ci5sZW4gPC0gZmlsdGVyKHRyLmxlbiwgc3BlY2llcyAhPSAiTWV0c2Nobmlrb3dpYSBiaWN1c3BpZGF0YSIpCmBgYAoKU2hvcnRlciBwcm90ZWlucyBzZWVtIHRvIGhhdmUgYSBsb3dlciBjb250ZW50IG9mIHRhbmRlbSByZXBlYXRzIGFzIGEgcGVyY2VudHJhZ2Ugb2YgdGhlaXIgbm9uIE5URCBwb3J0aW9uIG9mIHRoZSBwcm90ZWluLgpgYGB7cn0KdHIubGVuICU+JSAKICBtdXRhdGUoZ3JvdXAgPSBjdXQoc2VxTGVuLCBicmVha3MgPSBjKDAsNTAwLDEwMDAsMTUwMCw1MDAwKSwgCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjw1MDAgYWEiLCI8MTAwMCBhYSIsIjwxNTAwIGFhIiwiPj0xNTAwIGFhIikpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gZ3JvdXAsIHkgPSB0ci5wZXJjKSkgKyAKICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BLCB3aWR0aCA9IDAuNCkgKwogIGdlb21faml0dGVyKGFlcyhjb2xvciA9IGZydi5wcmVkKSwgd2lkdGggPSAwLjIsIHNpemUgPSAxLjUsIGFscGhhID0gMC44KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSAiRnVuZ2FsUlYiLCB2YWx1ZXMgPSBjKCJUUlVFIiA9ICJibGFjayIsIkZBTFNFIiA9ICJnb2xkMiIpKSArCiAgeWxhYigiJSBvZiB0b3RhbCBwcm90ZWluIChyZW1vdmUgUEYxMTc2NSkiKSArIHhsYWIoIlByb3RlaW4gbGVuZ3RoIikgKyAjY29vcmRfZmxpcCgpICsKICB0aGVtZV9jb3dwbG90KCkgKyBwYW5lbF9ib3JkZXIoY29sb3IgPSAiYmxhY2siKQpnZ3NhdmUoIi4uL291dHB1dC9pbWcvMjAyMjA2MjQtdGFuZGVtLXJlcGVhdC1wcm9wb3J0aW9uLnBuZyIsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNCkKYGBgClRlc3QgZm9yIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIHNlcXVlbmNlIGxlbmd0aCBhbmQgdGFuZGVtIHJlcGVhdCBjb250ZW50CmBgYHtyfQojIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzc1NDk2OTQvYWRkLXJlZ3Jlc3Npb24tbGluZS1lcXVhdGlvbi1hbmQtcjItb24tZ3JhcGgKIyAjIEdFVCBFUVVBVElPTiBBTkQgUi1TUVVBUkVEIEFTIFNUUklORwojICMgU09VUkNFOiBodHRwczovL2dyb3Vwcy5nb29nbGUuY29tL2ZvcnVtLyMhdG9waWMvZ2dwbG90Mi8xVGdILWtHNVhNQQojIG1vZGlmaWVkIGJ5IEJpbiBIZSAyMDIxLTA2LTI4CmxtX2VxIDwtIGZ1bmN0aW9uKG0pewogICAgZXEgPC0gc3Vic3RpdHV0ZShpdGFsaWMoeSkgPT0gYSArIGIgJS4lIGl0YWxpYyh4KSoiLCJ+fml0YWxpYyhyKV4yfiI9In5yMiwgCiAgICAgICAgIGxpc3QoYSA9IGZvcm1hdCh1bm5hbWUoY29lZihtKVsxXSksIGRpZ2l0cyA9IDQpLAogICAgICAgICAgICAgIGIgPSBmb3JtYXQodW5uYW1lKGNvZWYobSlbMl0pLCBkaWdpdHMgPSA0KSwKICAgICAgICAgICAgIHIyID0gZm9ybWF0KHN1bW1hcnkobSkkci5zcXVhcmVkLCBkaWdpdHMgPSAzKSkpCiAgICBhcy5jaGFyYWN0ZXIoYXMuZXhwcmVzc2lvbihlcSkpOwp9CgpsbS5vYmogPC0gbG0oc2VxTGVuIH4gdHJMZW4sIHRyLmxlbikKYGBgCgpgYGB7cn0KdHIubGVuICU+JSAKICBnZ3Bsb3QoYWVzKHggPSB0ckxlbiwgeSA9IHNlcUxlbikpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImdsbSIsIGZvcm11bGEgPSB5fngsIHNlID0gRkFMU0UpICsKICBnZW9tX3BvaW50KHNpemUgPSAxLCBhbHBoYSA9IDAuOSkgKyAKICBhbm5vdGF0ZShnZW9tID0gInRleHQiLCB4ID0gMjAwMCwgeSA9IDUwMCwgbGFiZWwgPSBsbV9lcShsbS5vYmopLCBwYXJzZSA9IFRSVUUsIHNpemUgPSByZWwoNSkpICsKICB4bGFiKCJUYW5kZW0gcmVwZWF0IGxlbmd0aCAoYWEpIikgKyB5bGFiKCJUb3RhbCBwcm90ZWluIGxlbmd0aCAoYWEpIikgKwogICNjb29yZF90cmFucyh4ID0gInNxcnQiLCB5ID0gInNxcnQiKSArCiAgI3NjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gIkZ1bmdhbFJWIiwgdmFsdWVzID0gYygiVFJVRSIgPSAiYmxhY2siLCJGQUxTRSIgPSAiZ29sZDIiKSkgKwogIHRoZW1lX2Nvd3Bsb3QoZm9udF9zaXplID0gMTYpICsgcGFuZWxfYm9yZGVyKGNvbG9yID0gImJsYWNrIikKZ2dzYXZlKCIuLi9vdXRwdXQvaW1nLzIwMjIwNjI1LXByb3RlaW4tbm9uTlRELWxlbmd0aC1kcml2ZW4tYnktdGFuZGVtLXJlcGVhdC5wbmciLCB3aWR0aCA9IDUsIGhlaWdodCA9IDQuNSkKYGBgCgo+IFRhbmRlbSByZXBlYXQgY29udGVudCBpcyBoaWdobHkgY29ycmVsYXRlZCB0byB0aGUgdG90YWwgcHJvdGVpbiBsZW5ndGgsIHdpdGggYW4gZXN0aW1hdGVkIHNsb3BlIG9mIGNsb3NlIHRvIDEsIHN1Z2dlc3RpbmcgdGhhdCBwcm90ZWluIGxlbmd0aCBldm9sdXRpb24gaXMgc3Ryb25nbHkgZHJpdmVuIGJ5IHRoZSBhY3F1aXJlbWVudCwgZXhwYW5zaW9uIG9yIGNvbnRyYWN0aW9uIG9mIHRhbmRlbSByZXBlYXRzLgoKU3VtbWFyeSBzdGF0cyBvZiBzZXF1ZW5jZSBsZW5ndGgKYGBge3J9CnRyLmxlbiAlPiUgc3VtbWFyaXplKGFjcm9zcyhjKHNlcUxlbiwgbm9uTlRETGVuKSwgbGlzdChtZWFuID0gbWVhbiwgc2QgPSBzZCwgbWVkaWFuID0gbWVkaWFuKSkpCmBgYAoKIyMgVEFOR08gcHJlZGljdGlvbiBvZiDOsi1hZ2dyZWdhdGlvbiBwcm9uZSBzZXF1ZW5jZXMKClRoZSBhbXlsb2lkLWxpa2UgJFxiZXRhJC1hZ2dyZWdhdGlvbiBwcm9uZSBzZXF1ZW5jZXMgaGF2ZSB0aGUgYWJpbGl0eSB0byBtZWRpYXRlIHNlbGYtYWdncmVnYXRpb24sIHdoaWNoIGJvb3N0cyB0aGUgbG9jYWwgY29uY2VudHJhdGlvbiBvZiB0aGUgYWRoZXNpbiBtb2xlY3VsZXMgb24gdGhlIGNlbGwtc3VyZmFjZS4gU2ltaWxhciB0byB0aGUgUy9UIGZyZXF1ZW5jeSBhYm92ZSwgd2Ugd291bGQgbGlrZSB0byB1c2UgdGhlIG91dHB1dCBmcm9tIHRoZSBwcmVkaWN0aW9uIGFsZ29yaXRobSwgVEFOR08sIHRvIHZpc3VsaXplIHRoZSBkaXN0cmlidXRpb24gb2Ygc3VjaCBzZXF1ZW5jZSBtb3RpZnMgYWxvbmcgdGhlIGxlbmd0aCBvZiB0aGUgWFBfMDI4ODg5MDMzIGhvbW9sb2cgc2VxdWVuY2VzLgoKVEFOR08gcHJlZGljdGlvbnMgYW5kIHRoZSBzdWJzZXF1ZW50IGV4dHJhY3Rpb24gb2YgJFxiZXRhJC1hZ2dyZWdhdGlvbiBwcm9uZSBzZXF1ZW5jZXMgYWNjb21wbGlzaGVkIGJ5IGAuLi9zY3JpcHQvcGFyc2VfdGFuZ29fb3V0cHV0LlJgCgpIb3cgbWFueSBUQU5HTyBwcmVkaWN0ZWQgzrItYWdncmVnYXRpb24gc2VxdWVuY2VzIGRvZXMgZWFjaCBob21vbG9nIGhhcywgZWl0aGVyIGluIHRoZSBlbnRpcmUgcHJvdGVpbiBvciBpbiB0aGUgbm9uLU5URCBwb3J0aW9uPyBUbyBkbyBzbyBJJ2xsIHRha2UgYWR2YW50YWdlIG9mIHRoZSBHUmFuZ2VzIHBhY2thZ2UgdG8gZGlzdGluZ3Vpc2ggVEFOR08gaGl0cyB0aGF0IGFyZSB3aXRoaW4gb3Igb3V0c2lkZSB0aGUgUEYxMTc2NSBkb21haW4ocykgZm9yIGVhY2ggcHJvdGVpbi4gRmlyc3QsIEkgbmVlZCB0byBjb252ZXJ0IHRoZSBmZWF0dXJlIHRhYmxlIGludG8gYSBHUmFuZ2VzIG9iamVjdCB3aXRoIHRoZSBzZXF1ZW5jZSBuYW1lcyB1c2VkIGFzIGNocm9tb3NvbWUgbmFtZXMgYW5kIHN0YXJ0IGFuZCBlbmQgYXMgdGhlIElSYW5nZXMgc3RhcnQgYW5kIGVuZC4gVGhlbiBJJ2xsIGNvbnZlcnQgdGhlIHRhbmdvIG91dHB1dCBhbHNvIGludG8gYSBHUmFuZ2VzIG9iamVjdCBpbiB0aGUgc2FtZSB3YXksIHdpdGggdGhlIGV4Y2VwdGlvbiBvZiBrZWVwaW5nIHRoZSBtZWRpYW4gYXMgdGhlIHNjb3JlIGZpZWxkLgpgYGB7cn0KIyByZWFkIGluIHRoZSBzdW1tYXJ5IHJlc3VsdHMKdGFuZ28gPC0gcmVhZF90c3YoIi4uL2RhdGEvdGFuZ29fc3VtbWFyeV90YWJsZS50c3YuZ3oiLCBjb2xfdHlwZXMgPSAiY2NpaWlkZGRpY2MiKSAlPiUgCiAgbGVmdF9qb2luKGJsYXN0SW5mbyAlPiUgc2VsZWN0KGlkID0gcGlkLCBuYW1lKSwgYnkgPSAiaWQiKSAlPiUgCiAgZmlsdGVyKCFpZCAlaW4lIE1iLnJtJHBpZCkKCnBmMTE3NjUuZ3IgPC0gcGYxMTc2NSAlPiUgCiAgc2VsZWN0KHNlcW5hbWUgPSBuYW1lLCBzdGFydCwgZW5kKSAlPiUgCiAgbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKGlnbm9yZS5zdHJhbmQgPSBUUlVFKQoKdGFuZ28uZ3IgPC0gdGFuZ28gJT4lIAogIHNlbGVjdChzZXFuYW1lID0gbmFtZSwgc3RhcnQsIGVuZCwgc2NvcmUgPSBtZWRpYW4pICU+JSAKICBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUoa2VlcC5leHRyYS5jb2x1bW5zID0gVFJVRSwgaWdub3JlLnN0cmFuZCA9IFRSVUUpCgojIGNvdW50IHRoZSBudW1iZXIgb2YgdGFuZ28gaGl0cyBpbiB0aGUgcGYxMTc2NSBkb21haW4KdGFuZ28uZ3IuaW4gPC0gc3Vic2V0QnlPdmVybGFwcyh0YW5nby5nciwgcGYxMTc2NS5ncikgJT4lIAogIGFzX3RpYmJsZSgpICU+JSAKICBtdXRhdGUoSW5OVEQgPSBUUlVFKSAlPiUgCiAgc2VsZWN0KG5hbWUgPSBzZXFuYW1lcywgc3RhcnQsIGVuZCwgSW5OVEQpCgp0YW5nbyA8LSB0YW5nbyAlPiUgCiAgbXV0YXRlKEluTlREID0gRkFMU0UpICU+JSAKICByb3dzX3VwZGF0ZSh0YW5nby5nci5pbiwgYnkgPSBjKCJuYW1lIiwgInN0YXJ0IiwgImVuZCIpKQoKIyByZW1vdmUgaW50ZXJtZWRpYXRlIG9iamVjdHMKcm0obGlzdCA9IGMoInRhbmdvLmdyIiwgInRhbmdvLmdyLmluIiwgInBmMTE3NjUuZ3IiKSkKYGBgCgpDYWxjdWxhdGUgc3VtbWFyeSBzdGF0aXN0aWNzOgpgYGB7cn0KdGFuZ28uc3VtIDwtIHRhbmdvICU+JSAKICBncm91cF9ieShuYW1lKSAlPiUgCiAgc3VtbWFyaXplKG4ubnRkID0gc3VtKEluTlREKSwgbi5udGQuZ3QzMCA9IHN1bShyb3VuZChtZWRpYW4sMCkgPj0gMzAgJiBJbk5URCksCiAgICAgICAgICAgIG4ucmVzdCA9IHN1bSghSW5OVEQpLCBuLnJlc3QuZ3QzMCA9IHN1bShyb3VuZChtZWRpYW4sMCkgPj0gMzAgJiAhSW5OVEQpKSAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChibGFzdEluZm8sIG5hbWUsIHNlcUxlbiA9IHNsZW4pLCBieSA9ICJuYW1lIikKCmJpbmRfcm93cygKICBQRjExNzY1ID0gdGFibGUoY3V0KHRhbmdvLnN1bSRuLm50ZCwgYnJlYWtzID0gYygwLDEsMyw1LDEwLEluZiksIHJpZ2h0ID0gRkFMU0UpKSwKICBgUEYxMTc2NSwgPjMwYCA9IHRhYmxlKGN1dCh0YW5nby5zdW0kbi5udGQuZ3QzMCwgYnJlYWtzID0gYygwLDEsMyw1LDEwLEluZiksIHJpZ2h0ID0gRkFMU0UpKSwKICBSZXN0ID0gdGFibGUoY3V0KHRhbmdvLnN1bSRuLnJlc3QsIGJyZWFrcyA9IGMoMCwxLDMsNSwxMCxJbmYpLCByaWdodCA9IEZBTFNFKSksCiAgYFJlc3QsID4zMGAgPSB0YWJsZShjdXQodGFuZ28uc3VtJG4ucmVzdC5ndDMwLCBicmVha3MgPSBjKDAsMSwzLDUsMTAsSW5mKSwgcmlnaHQgPSBGQUxTRSkpLAogIC5pZCA9ICJncm91cCIKKQpgYGAKCj4gSW4gc3VtLCB0aGVyZSBhcmUgbW9yZSBUQU5HTyBwcmVkaWN0ZWQgzrItYWdncmVnYXRpb24gcHJvbmUgc2VxdWVuY2VzIGluIHRoZSBQRjExNzY1IGRvbWFpbiB0aGFuIGluIHRoZSByZXN0IG9mIHRoZSBwcm90ZWlucy4gVGhpcyBpcyBsaWtlbHkgYSByZXN1bHQgb2YgbWFueSBzaG9ydCBwcm90ZWlucyBub3QgaGF2aW5nIGFuIGV4dGVuc2l2ZSBudW1iZXIuCgpFeGFtaW5lIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIG51bWJlciBvZiBUQU5HTyBoaXRzIGFuZCB0aGVpciBzcGF0aWFsIG9yZ2FuaXphdGlvbiB3aXRoaW4gZWFjaCBwcm90ZWluLiBPbmUgZGlmZmVyZW5jZSBmcm9tIG15IHByZXZpb3VzIGFuYWx5c2lzIGlzIHRoYXQgSSBkb24ndCBleGNsdWRlIHRoZSBoaXRzIGluIHRoZSBQRjExNzY1IGRvbWFpbiBmcm9tIHRoZSB0b3RhbCBjb3VudC4KYGBge3J9CiMgZmlyc3QgY291bnQgdGhlIG51bWJlciBvZiBvdXQtb2YtTlRELCBtZWRpYW4gc2NvcmUgPj0gMzAgaGl0cyBwZXIgc2VxdWVuY2UKbW90aWYucGVyLnNlcSA8LSB0YW5nbyAlPiUgCiAgZ3JvdXBfYnkobmFtZSkgJT4lIAogIHN1bW1hcml6ZShuLmFsbCA9IHN1bShyb3VuZChtZWRpYW4sIDApID49IDMwKSkKCiMgbmV4dCB3ZSB3aWxsIGZpbHRlciB0aGUgdGFuZ28gZGF0YXNldCBpbiBvcmRlciB0byByZWNhbGN1bGF0ZSB0aGUgaW50ZXJ2YWxzCiMgdGhpcyB3aWxsIHJlc3VsdCBpbiAxNCBzZXF1ZW5jZXMgdG8gYmUgZHJvcHBlZCBzaW5jZSB0aGV5IGhhdmUgMCBoaXRzIG1lZXRpbmcKIyB0aGUgY3JpdGVyaWEuIHdlIHdpbGwgYWRkIHRoZW0gYmFjayBieSByaWdodF9qb2luKCkgd2l0aCB0aGUgdGliYmxlIGFib3ZlCm1vdGlmLnBlci5zZXEgPC0gdGFuZ28gJT4lIAogICMgbGltaXQgdG8gaGl0cyB3aXRoIG1lZGlhbiBzY29yZSA+PSAzMAogIGZpbHRlcihyb3VuZChtZWRpYW4sMCkgPj0gMzApICU+JSAKICBncm91cF9ieShuYW1lKSAlPiUgCiAgIyByZWNhbGN1bGF0ZSB0aGUgaW50ZXJ2YWwgc2luY2Ugd2UgYXJlIG5vdyBsaW1pdGluZyB0aGUgaGl0cyB0byA+PSAzMAogIG11dGF0ZShpbnRlcnZhbCA9IHN0YXJ0IC0gbGFnKGVuZCkgLSAxKSAlPiUgCiAgIyBzdW1tYXJpemUgdGhlIHJlc3VsdHMgYXQgYSBzZXF1ZW5jZSBsZXZlbAogIHN1bW1hcml6ZShuLnR5cGUgPSBsZW5ndGgodW5pcXVlKHNlcSkpLAogICAgICAgICAgICBuLmFsbCA9IG4oKSwKICAgICAgICAgICAgbWVkU2NvcmUgPSByb3VuZChtZWFuKG1lZGlhbiksMSksCiAgICAgICAgICAgIElWVCA9IHJvdW5kKG1lYW4oaXZ0KSwyKSwKICAgICAgICAgICAgYXZnLmludHYgPSByb3VuZChtZWFuKGludGVydmFsLCBuYS5ybSA9IFQpLDEpLCAKICAgICAgICAgICAgSVFSLmludHYgPSByb3VuZChJUVIoaW50ZXJ2YWwsIG5hLnJtID0gVCkvMS4zNDkgLDEpLAogICAgICAgICAgICAjIG1lZGlhbiBhYnNvbHV0ZSBkZXZpYXRpb24gaXMgYSByb2J1c3QgbWVhc3VyZSBvZiB0aGUgc2NhbGUgcGFyYW1ldGVyCiAgICAgICAgICAgICMgaHR0cHM6Ly93d3cucmRvY3VtZW50YXRpb24ub3JnL3BhY2thZ2VzL3N0YXRzL3ZlcnNpb25zLzMuNi4yL3RvcGljcy9tYWQKICAgICAgICAgICAgbWFkLmludHYgPSByb3VuZChtYWQoaW50ZXJ2YWwsIG5hLnJtID0gVCksMSksCiAgICAgICAgICAgIHNlcXMgPSBwYXN0ZSh1bmlxdWUoc2VxKSwgY29sbGFwc2UgPSAiLCIpLAogICAgICAgICAgICAuZ3JvdXBzID0gImRyb3BfbGFzdCIpICU+JSAKICByaWdodF9qb2luKG1vdGlmLnBlci5zZXEsIGJ5ID0gYygibmFtZSIsICJuLmFsbCIpKSAlPiUgCiAgYXJyYW5nZShkZXNjKG4uYWxsKSwgZGVzYyhtYWQuaW50dikpCkRUOjpkYXRhdGFibGUobW90aWYucGVyLnNlcSkKCiMgYWRkIGV4dHJhIGluZm9ybWF0aW9uIGZvciBwbG90dGluZyBiZWxvdwptb3RpZi5wZXIuc2VxIDwtIG1vdGlmLnBlci5zZXEgJT4lIAogIGxlZnRfam9pbihzZWxlY3QoYmxhc3RJbmZvLCBzcGVjaWVzLCBuYW1lKSwgYnkgPSAibmFtZSIpICU+JSAKICBtdXRhdGUobWFkLmludHYgPSBpZmVsc2Uobi5hbGwgPiAyLCBtYWQuaW50diwgTkEpLAogICAgICAgICByZWcuc3BhY2VkID0gaWZlbHNlKG4uYWxsID49IDUgJiBtYWQuaW50diA8IDUsIFRSVUUsIEZBTFNFKSwKICAgICAgICAgc3BlY2llcyA9IG9yZGVyZWQoc3BlY2llcywgbGV2ZWxzID0gZ2V0X3RheGFfbmFtZShwLnRyZWUpKSkKYGBgCgo8IS0tIEV4cG9ydCB0aGUgdGFuZ28gbW90aWYgcGVyIHNlcSByZXN1bHQgLS0+CjwhLS0gYGBge3J9IC0tPgo8IS0tIG1vdGlmLnBlci5zZXExICU+JSAgLS0+CjwhLS0gICBtdXRhdGUoaWQgPSBnc3ViKCJfW2EtekEtWl0rJCIsICIiLCBuYW1lKSwgLS0+CjwhLS0gICAgICAgICAgc3BlY2llcyA9IGdzdWIoIi4qXyhbQS1aXSkoW2Etel0rKSQiLCAiXFwxXFwuIFxcMiIsIG5hbWUpKSAlPiUgIC0tPgo8IS0tICAgc2VsZWN0KGlkLCBzcGVjaWVzLCBzcGVjaWVzX2dyLCBuLnR5cGUsIG4uYWxsLCBhdmcuaW50diwgbWFkLmludHYsIHNlcXMpICU+JSAgLS0+CjwhLS0gICB3cml0ZV90c3YoIm91dHB1dC90YW5nby8yMDIxMDkwNC10YW5nby1zdW1tYXJ5LXRhYmxlLnRzdiIpIC0tPgo8IS0tIGBgYCAtLT4KCmBgYHtyfQojICBtdXRhdGUoQ2xhZGUyID0gaWZlbHNlKHNwZWNpZXMgJWluJSBjbGF2aXNwb3JhLCAiQ2xhdmlzcG9yYSIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHNwZWNpZXMgJWluJSBjYW5kaWRhLCAiQ2FuZGlkYSIsIAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2Uoc3BlY2llcyAlaW4lIHNhY2NoYXJvLCAiU2FjY2hhcm9teWNldGFjZWFlIiwgIm90aGVyIikpKSkKcDAgPC0gbW90aWYucGVyLnNlcSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gc3BlY2llcykpICsgZ2VvbV9iYXIoKSArIGNvb3JkX2ZsaXAoKSArCiAgIyB0aGFua3MgdG8gaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMTA4MzQzODIvZ2dwbG90Mi1rZWVwLXVudXNlZC1sZXZlbHMtYmFycGxvdAogIHNjYWxlX3hfZGlzY3JldGUoZHJvcCA9IEZBTFNFKSArCiAgc2NhbGVfeV9jb250aW51b3VzKG1pbm9yX2JyZWFrcyA9IE5VTEwpICsgCiAgeWxhYigiSGlsIGZhbWlseSBzaXplIikKCmNvbC5yZWdzcGMgPC0gYygiVFJVRSIgPSAiI2FmODQwMCIsICJGQUxTRSIgPSBhbHBoYSgiZ3JleTMwIiwgMC41KSkKcDEgPC0gbW90aWYucGVyLnNlcSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gc3BlY2llcywgeSA9IG4uYWxsKSkgKyAKICBnZW9tX2ppdHRlcihhZXMoY29sb3IgPSByZWcuc3BhY2VkLCBzaXplID0gcmVnLnNwYWNlZCksIHdpZHRoID0gMC4yLCBoZWlnaHQgPSAwKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShkcm9wID0gRkFMU0UpICsKICBzY2FsZV9zaXplX21hbnVhbCh2YWx1ZXMgPSBjKC44LDEuOCksIGd1aWRlID0gIm5vbmUiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSAiUmVndWxhcmx5IHNwYWNlZCIsIHZhbHVlcyA9IGNvbC5yZWdzcGMpICsKICBjb29yZF9mbGlwKCkgKyB5bGFiKCIjIFRBTkdPIGhpdHMvcHJvdGVpbiIpIyArCiAgI3NjYWxlX3lfY29udGludW91cyh0cmFucyA9ICJwc2V1ZG9fbG9nIiwgYnJlYWtzID0gYygwLDEsMiw1LDEwLDIwLDQwKSwKICAjICAgICAgICAgICAgICAgICAgIG1pbm9yX2JyZWFrcyA9IE5VTEwpCmxlZ2VuZCA8LSBnZXRfbGVnZW5kKHAxICsgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAxKSwgcGNoID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAxKSkgKwogICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSkKICAKcDIgPC0gbW90aWYucGVyLnNlcSAlPiUgCiAgbXV0YXRlKG1hZC5pbnR2ID0gaWZlbHNlKGlzLm5hKG1hZC5pbnR2KSwgNTAwLCBtYWQuaW50dikpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBzcGVjaWVzLCB5ID0gbWFkLmludHYpKSArIAogIGdlb21faml0dGVyKGFlcyhjb2xvciA9IHJlZy5zcGFjZWQpLCBzaXplID0gMi4yLCB3aWR0aCA9IDAuMywgaGVpZ2h0ID0gMCkgKwogICNnZW9tX2RvdHBsb3QoYWVzKGZpbGwgPSByZWcuc3BhY2VkKSwgYmluYXhpcyA9ICJ5IiwgYmlud2lkdGggPSAwLjUsIAogICMgICAgICAgICAgICAgc3RhY2tkaXIgPSAiY2VudGVyIiwgd2lkdGggPSAwLjMsIGJpbnBvc2l0aW9ucyA9ICJhbGwiKSArCiAgI3NjYWxlX3NoYXBlX21hbnVhbChuYW1lID0gIlJlZ3VsYXJseSBzcGFjZWQiLCB2YWx1ZXMgPSBjKDIxLCAxOSkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJSZWd1bGFybHkgc3BhY2VkIiwgdmFsdWVzID0gY29sLnJlZ3NwYykgKwogIHNjYWxlX3lfY29udGludW91cyh0cmFucyA9ICJwc2V1ZG9fbG9nIiwgCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoMCw1LDI1LDEwMCw1MDApLCBtaW5vcl9icmVha3MgPSBOVUxMKSArCiAgY29vcmRfZmxpcCgpICsgeWxhYigiVmFyaWF0aW9uIGluIHNwYWNpbmcgKE1BRCkiKQoKcDMgPC0gdGhlbWVfYncoYmFzZV9zaXplID0gMTQpICsgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpwcm93IDwtIHBsb3RfZ3JpZChwMCArIHAzLCBwMSArIHAzLCBuY29sID0gMiwgcmVsX3dpZHRocyA9IGMoMS41LDIpKQoKcGxvdF9ncmlkKGxlZ2VuZCwgcHJvdywgbmNvbCA9IDEsIHJlbF9oZWlnaHRzID0gYyguMSwxKSkKI3Bsb3RfZ3JpZChwLnRyZWUsIHAwK3AzLCBwMSArIHAzLCBucm93ID0gMSwgYWxpZ24gPSAiaCIsIHJlbF93aWR0aHMgPSBjKDQsMSwyKSwgc2NhbGUgPSBjKDEsMC45LDAuOSkpCgpnZ3NhdmUoIi4uL291dHB1dC9pbWcvMjAyMjA5MTUtdGFuZ28taGl0cy1udW1iZXItYW5kLWludGVydmFsLnBuZyIsIHdpZHRoID0zLjUsIGhlaWdodCA9IDQuNSkKYGBgCgp3ZSBuZWVkIGEgc3BlY2llcyB0cmVlIG9uIHRoZSBzaWRlCmBgYHtyfQpwLnNwcy50cmVlLnNpZGUgPC0gZ2d0cmVlKHNwcy50cmVlLCBsYWRkZXJpemUgPSBGQUxTRSkgKyB4bGltKDAsMi40KSArIHNjYWxlX3lfcmV2ZXJzZSgpICsKICBnZW9tX3RpcGxhYihhZXMobGFiZWwgPSBwYXN0ZShzdHJfc3ViKHdvcmQobGFiZWwsIDEpLCAxLCAxKSwgd29yZChsYWJlbCwgMiksIHNlcCA9ICIuICIpKSwKICAgICAgICAgICAgICBzaXplID0gMy4yLCBmb250ZmFjZSA9ICJpdGFsaWMiLCBhbGlnbiA9IFRSVUUsIGxpbmVzaXplID0gMC4xLCBvZmZzZXQgPSAwLjA1KSArCiAgI2dlb21fdHJlZXNjYWxlKHggPSAwLCB3aWR0aCA9IDAuMiwgbGluZXNpemUgPSAxLjIpICsKICBnZW9tX2hpbGlnaHQobm9kZSA9IGNsYWRlWyJNRFIiXSwgZmlsbCA9ICIjN0YwMEZGIiwgYWxwaGEgPSAwLjE1KSAgKyAjIE1EUgogIGdlb21faGlsaWdodChub2RlID0gY2xhZGVbIkNhTG8iXSwgZmlsbCA9ICJwaW5rIiwgYWxwaGEgPSAwLjI1KSAgICArICMgQ2FuZGlkYS9Mb2RkZXJvbXljZXMKICBnZW9tX2hpbGlnaHQobm9kZSA9IGNsYWRlWyJnbGFicmF0YSJdLCBmaWxsID0gInN0ZWVsYmx1ZSIsIGFscGhhID0gMC4xNSkgICsgIyBnbGFicmF0YQogICNnZW9tX2NsYWRlbGFiZWwobm9kZSA9IGNsYWRlWyJNRFIiXSwgIGxhYmVsID0gIk1EUiIsIG9mZnNldCA9IDEuNSwjIGNvbG9yID0gInB1cnBsZSIsCiAgIyAgICAgICAgICAgICAgICBvZmZzZXQudGV4dCA9IDAuMDUsIGFuZ2xlID0gMjcwLCBoanVzdCA9IC41LCBleHRlbmQgPSAwLjUpICsjIE1EUgogICNnZW9tX2NsYWRlbGFiZWwobm9kZSA9IGNsYWRlWyJDYUxvIl0sICBsYWJlbCA9ICJDYW5kaWRhL1xuTG9kZGVyb215Y2VzIiwgb2Zmc2V0ID0gMS40NywjIGNvbG9yID0gImhvdHBpbmsyIiwKICAjICAgICAgICAgICAgICAgIG9mZnNldC50ZXh0ID0gMC4xLCBhbmdsZSA9IDI3MCwgaGp1c3QgPSAuNSwgZXh0ZW5kID0gMC41LCBmb250c2l6ZSA9IDMuNSkgKyAjIGFsYmljYW5zCiAgI2dlb21fY2xhZGVsYWJlbChub2RlID0gY2xhZGVbImdsYWJyYXRhIl0sICBsYWJlbCA9ICJnbGFicmF0YSIsIG9mZnNldCA9IDEuMzgsIyBjb2xvciA9ICJzdGVlbGJsdWUiLCAKICAjICAgICAgICAgICAgICAgIG9mZnNldC50ZXh0ID0gMC4wNSwgYW5nbGUgPSAyNzAsIGhqdXN0ID0gLjUsIGV4dGVuZCA9IDAuNSkgKyMgZ2xhYnJhdGEKICBnZW9tX3RpcHBvaW50KGFlcyhjb2xvciA9IHBhdGhvZ2VuKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSAgYygiY3J1c3RhY2VhbiIgPSAiIzZhNWFjZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJodW1hbiIgPSAiI2QxNDk0OSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiaHVtYW4gKHJhcmUpIiA9ICJzdGVlbGJsdWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibm8gcmVwb3J0IiA9ICJncmF5MjAiKSwKICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSAibm9uZSIpCnAuc3BzLnRyZWUuc2lkZQpnZ3NhdmUoZmlsZW5hbWUgPSAiLi4vb3V0cHV0L2ltZy8yMDIyMDkxNi1zcGVjaWVzLXRyZWUtc2lkZS5wbmciLCB3aWR0aCA9IDMuNSwgaGVpZ2h0ID0gNSkKYGBgCgoKIyBGZWF0dXJlIG1hcCBmb3IgaG9tb2xvZ3MKVGhlIGdvYWwgaXMgdG8gcHJvZHVjZSBhIHNjaGVtYXRpYyBwbG90IGZvciBlYWNoIGhvbW9sb2cgb3V0bGluaW5nIHRoZWlyIG1haW4gZmVhdHVyZXMsIHN1Y2ggYXMgdGhlIGxvY2F0aW9ucyBvZiB0aGUgUEZhbSBkb21haW5zIChtYWlubHkgdGhlIEh5cF9yZWdfQ1dQKSwgbG9jYXRpb25zIG9mIHRoZSBzaWduYWwgcGVwdGlkZSBhbmQgR1BJLWFuY2hvciwgZGlzdHJpYnV0aW9uIG9mIFRBTkdPIHNlcXVlbmNlcy4gTm90ZSB0aGF0IGFsbCB0aGVzZSBmZWF0dXJlcyBjYW4gYmUgcmVwcmVzZW50ZWQgYXMgYSByYW5nZSB3aXRoIGFzc29jaWF0ZWQgbWV0YWRhdGEuIFNvIHRoZSBmaXJzdCBzdGVwIGlzIHRvIGNvbGxlY3QgdGhlIGNvb3JkaW5hdGVzIG9mIHRoZSBmZWF0dXJlcwoKIyMgR2VuZSB0cmVlIGZvciBvcmdhbml6aW5nIHRoZSBmZWF0dXJlcwpgYGB7cn0KIyBsb2FkIHRoZSBnZW5lIHRyZWUKZ2VuZS50cmVlIDwtIHJlYWQubmh4KGZpbGUgPSAiLi4vZGF0YS8yMDIyMDUxMi1nZW5lcmF4LWNsdXN0YWxvLXNoZW4yMDE4LXdTY2VyLWdlbmUtdHJlZS5uaHgiKSAlPiUgCiAgZHJvcC50aXAodGlwID0gTWIucm0kbmFtZSkKIyBhZGQgc3VwcGxlbWVudGFsIGluZm9ybWF0aW9uCmNsYWRlcyA8LSBzcHMudHJlZSAlPiUgYXNfdGliYmxlKCkgJT4lIHNlbGVjdCh0cmVlTmFtZSwgZ3JvdXApICU+JSBuYS5vbWl0KCkKZ2VuZS50cmVlIDwtIGxlZnRfam9pbihnZW5lLnRyZWUsIHNlbGVjdChzcHNJbmZvLCB0cmVlTmFtZSwgZmFtaWx5KSwgYnkgPSBjKCJTIiA9ICJ0cmVlTmFtZSIpKSAlPiUgCiAgbGVmdF9qb2luKGNsYWRlcywgYnkgPSBjKCJTIiA9ICJ0cmVlTmFtZSIpKSMgJT4lIAogICNtdXRhdGUoZmFtaWx5ID0gZm9yY2F0czo6ZmN0X3JlbGV2ZWwoZmFtaWx5LCAiTWV0c2Nobmlrb3dpYWNlYWUiLCBhZnRlciA9IEluZikpCiMgbGFiZWwgc2VsZWN0ZWQgc3BlY2llcyB0byBzaG93IHRoZSBjbHVzdGVyaW5nCnNlbGVjdGVkX25vZGVzIDwtIGdlbmUudHJlZSAlPiUgYXNfdGliYmxlKCkgJT4lIAogIGZpbHRlcihTICVpbiUgYygiQ2FuZGlkYV9hbGJpY2FucyIsICJDYW5kaWRhX2dsYWJyYXRhIiwgIkNhbmRpZGFfYXVyaXMiKSkgJT4lIAogIHB1bGwobm9kZSkKIyBjb2xvciBieSBmYW1pbHkKY2xhZGUuY29scyA8LSBjKAogICJDYUxvIiA9ICJmaXJlYnJpY2siLAogICJNRFIiID0gIiM3RjAwRkYiLAogICJnbGFicmF0YSIgPSAic3RlZWxibHVlIgopCmBgYAoKYGBge3IgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9N30KcC5nZW5lLnRyZWUgPC0gZ2d0cmVlKGdlbmUudHJlZSwgc2l6ZSA9IDAuNCkgKyB4bGltKDAsNCkgKyAKICAjZ2VvbV9ub2RlcG9pbnQoYWVzKGZpbGwgPSBEKSwgZGF0YSA9IHRkX2ZpbHRlcihEID09ICJZIiksIHNoYXBlID0gMjEsIHNpemUgPSAxLCBjb2xvciA9ICJyZWQiKSArIAogIGdlb21fdGlwcG9pbnQoYWVzKGNvbG9yID0gZ3JvdXApLCBzaXplID0gMSkgKwogIGdlb21fdGlwbGFiKGFlcyhjb2xvciA9IGZhbWlseSksCiAgICAgICAgICAgICAgIGFsaWduID0gVFJVRSwgbGluZXNpemUgPSAwLjEsIHNpemUgPSAxLCBvZmZzZXQgPSAwLjA1KSArCiAgZ2VvbV9ub2RlbGFiKGFlcyh4ID0gYnJhbmNoLCBsYWJlbCA9IG5vZGUpLCBzaXplID0gMSkgKwogICNnZW9tX2NsYWRlbGFiKG5vZGUgPSAzNTcsICBsYWJlbCA9ICJNLiBiaWN1c3BpZGF0YSIsIG9mZnNldC50ZXh0ID0gMC4wNSwgYW5nbGUgPSAyNzAsIGhqdXN0ID0gLjUsIGV4dGVuZCA9IDAuNSkgKwogICNnZW9tX3RleHQobGFiZWwgPSAiRCIsIGRhdGEgPSB0ZF9maWx0ZXIoRCA9PSAiWSIpLCBoanVzdCA9IC0wLjQsIHNpemUgPSAxLjUsIGNvbG9yID0gInJlZCIpIyArCgogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gIkNsYWRlIiwgdmFsdWVzID0gY2xhZGUuY29scykjICsKcC5nZW5lLnRyZWUKZ2dzYXZlKGZpbGVuYW1lID0gIi4uL291dHB1dC9pbWcvMjAyMjA5MTYtZ2VuZS10cmVlLXNpZGUucG5nIiwgd2lkdGggPSA1LCBoZWlnaHQgPSA3KQpgYGAKCkV4dHJhY3QgZ2VuZSB0cmVlIG9yZGVyCmBgYHtyfQpnZW5ldHJlZU9yZGVyIDwtIGdldF90YXhhX25hbWUocC5nZW5lLnRyZWUpCmBgYAoKIyMgT3JnYW5pemUgYW5kIGNvbWJpbmUgdGhlIHRhbmRlbSByZXBlYXRzIGZlYXR1cmVzCmBgYHtyfQojIHN1bW1hcml6ZSBzdGF0cyBvZiB0YW5kZW0gcmVwZWF0cwpyZXBlYXRzIDwtIHRhbmRlbSAlPiUgCiAgZ3JvdXBfYnkodHlwZSwgcGVyaW9kKSAlPiUgCiAgc3VtbWFyaXplKG4gPSBuKCksIGNvcHlNZWFuID0gbWVhbihjb3B5TiksIC5ncm91cHMgPSAiZHJvcCIpICU+JSAKICBtdXRhdGUobGVuZ3RoID0gcGVyaW9kICogY29weU1lYW4pCgp0ciA8LSB0YW5kZW0gJT4lIAogIGxlZnRfam9pbihzZWxlY3QocmVwZWF0cywgdHlwZSwgY29weU1lYW4pLCBieSA9IGMoInR5cGUiID0gInR5cGUiKSkgJT4lIAogIGZpbHRlcihuYW1lICVpbiUgZ2VuZXRyZWVPcmRlcikgJT4lIAogIG11dGF0ZSh0eXBlID0gcGFzdGUwKCJUUi0iLCB0eXBlKSwKICAgICAgICAgdGlwID0gcGFzdGUwKGNvbnNlbnN1c19ub2dhcCwKICAgICAgICAgICAgICAgICAgICAgICJcbnR5cGU6ICIsIHR5cGUsCiAgICAgICAgICAgICAgICAgICAgICAiXG5wZXJpb2Q6ICIsIHBlcmlvZCwgCiAgICAgICAgICAgICAgICAgICAgICAiXG5jb3B5TjogIiwgY29weU1lYW4pLAogICAgICAgICBuYW1lID0gb3JkZXJlZChuYW1lLCBsZXZlbHMgPSByZXYoZ2VuZXRyZWVPcmRlcikpKSAlPiUgCiAgc2VsZWN0KG5hbWUsIHR5cGUsIHN0YXJ0LCBlbmQsIHRpcCkKYGBgCgpNYWtlIGEgYHNlcUxlbmAgb2JqZWN0IHRvIGRyYXcgdGhlIG92ZXJhbGwgbGVuZ3RoIG9mIGVhY2ggcHJvdGVpbgpgYGB7cn0Kc2VxTGVuIDwtIGJsYXN0SW5mbyAlPiUgCiAgZmlsdGVyKG5hbWUgJWluJSBnZW5ldHJlZU9yZGVyKSAlPiUgCiAgbXV0YXRlKHN0YXJ0ID0gMSwgCiAgICAgICAgIG5hbWUgPSBvcmRlcmVkKG5hbWUsIGxldmVscyA9IHJldihnZW5ldHJlZU9yZGVyKSkpICU+JSAKICBzZWxlY3QobmFtZSwgc3RhcnQsIGVuZCA9IHNsZW4pCmBgYAoKYGBge3J9CiMgR1BJLWFuY2hvcgojIHVzZSBwcmVkLmdwaQojIGZlYXR1cmUgc2V0CiMgc3RydWN0dXJlOiBpZCAgZmVhdHVyZSAgc3RhcnQgIGVuZApmZWF0dXJlIDwtIGJpbmRfcm93cygKICBIeXBoYWxfcmVnX0NXUCA9IHBmMTE3NjUsCiAgIyBleHRlbmQgdGhlIHNpZ25hbCBwZXB0aWRlIHNlZ21lbnQgYnkgMTAgYW1pbm8gYWNpZHMgdG8gbWFrZSBpdCBtb3JlIHZpc2libGUKICBgU2lnbmFsIFBlcHRpZGVgID0gc2lnbmFscDYgJT4lIG11dGF0ZShlbmQgPSBlbmQgKyAxMCkgJT4lIHNlbGVjdChuYW1lLCBzdGFydCwgZW5kKSwKICAjIGV4dGVuZCB0aGUgR1BJLWFuY2hvciBDLXRlcm1pbnVzIHNlZ21lbnQgYnkgMjAgYW1pbm8gYWNpZHMgdG8gbWFrZSBpdCBtb3JlIHZpc2libGUKICBgR1BJLWFuY2hvcmAgPSBwcmVkLmdwaSAlPiUgZmlsdGVyKGdwaS5wcmVkKSAlPiUKICAgIGxlZnRfam9pbihzZWxlY3QoYmxhc3RJbmZvLCBuYW1lLCBzbGVuKSwgYnkgPSAibmFtZSIpICU+JSAKICAgIG11dGF0ZShzdGFydCA9IGNsZWF2ZVBvcy0xMCwgZW5kID0gc2xlbikgJT4lIAogICAgc2VsZWN0KG5hbWUsIHN0YXJ0LCBlbmQpLAogIGBUYW5kZW0gUmVwZWF0c2AgPSB0ciAlPiUgc2VsZWN0KG5hbWUsIHN0YXJ0LCBlbmQpLAogIC5pZCA9ICJ0eXBlIgopICU+JSBmaWx0ZXIoIW5hbWUgJWluJSBNYi5ybSRuYW1lKQoKZmVhdHVyZSA8LSBmZWF0dXJlICU+JSAKICBtdXRhdGUobmFtZSA9IG9yZGVyZWQobmFtZSwgbGV2ZWxzID0gcmV2KGdlbmV0cmVlT3JkZXIpKSwKICAgICAgICAgdHlwZSA9IG9yZGVyZWQodHlwZSwgbGV2ZWxzID0gYygiSHlwaGFsX3JlZ19DV1AiLCAiU2lnbmFsIFBlcHRpZGUiLCAiR1BJLWFuY2hvciIsICJUYW5kZW0gUmVwZWF0cyIpKSkKZmVhdHVyZS5jb2xvcnMgPC0gYygiSHlwaGFsX3JlZ19DV1AiID0gIiMzZDg1YzYiLCAiU2lnbmFsIFBlcHRpZGUiID0gIiNjYzAwMDAiLCAiR1BJLWFuY2hvciIgPSAiIzZhM2Q5YSIsICJUYW5kZW0gUmVwZWF0cyIgPSAiI2FmODQwMGJiIikKYGBgCgojIyBQbG90IGRvbWFpbiBvcmdhbml6YXRpb24KYGBge3IgcGxvdF90YW5kZW1fcmVwZWF0cywgd2FybmluZz1GQUxTRX0KaCA9IDEuMgojIHBsb3QKcDAgPC0gZ2dwbG90KHNlcUxlbiwgYWVzKHggPSBuYW1lLCB5ID0gc3RhcnQsIHhlbmQgPSBuYW1lLCB5ZW5kID0gZW5kKSkgKyAKICBnZW9tX3NlZ21lbnQoY29sb3IgPSAiZ3JheTgwIiwgc2l6ZSA9IGgpCnAxIDwtIGdlb21fc2VnbWVudChkYXRhID0gZmVhdHVyZSwgIGFlcyhjb2xvciA9IHR5cGUpLCBzaXplID0gaCkKcDIgPC0gZ2VvbV9zZWdtZW50KGRhdGEgPSB0YW5kZW0uZGl2LCBhZXMoeCA9IG5hbWUsIHhlbmQgPSBuYW1lLCB5ID0gZGl2LCB5ZW5kID0gZGl2ICsgMS41KSwKICAgICAgICAgICAgICAgICAgIHNpemUgPSBoLCBjb2xvciA9ICJ3aGl0ZSIpCnAzIDwtIHAwICsgcDEgKyBjb29yZF9mbGlwKCkgKyB0aGVtZV9jbGFzc2ljKCkgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gZmVhdHVyZS5jb2xvcnMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKDAuMDIsIDAuMDIpKSkgKwogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzKSwgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMubGluZS55ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy5saW5lLnggPSBlbGVtZW50X2JsYW5rKCksIyBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gYygwLjgsIDAuOSksIAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLCAKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBhbHBoYSgibGlnaHRibHVlIiwwLjEpKSkgKwogIGxhYnMoeSA9ICJQb3NpdGlvbiBpbiBzZXF1ZW5jZSIsIHggPSAiU2VxdWVuY2VzIiwgY29sb3IgPSAiRkVBVFVSRVMiKQojcGxvdF9ncmlkKHAuZ3RyZWUsIHAzLCBuY29sID0gMiwgYWxpZ24gPSAndicsIHJlbF93aWR0aHMgPSBjKDEsMiksIHNjYWxlID0gYygxLjAxLDEpKQpnZ3NhdmUoIi4uL291dHB1dC9pbWcvMjAyMjA5MTYtZG9tYWluLXRhbmRlbS1yZXBlYXRzLnBuZyIsIHBsb3QgPSBwMywgd2lkdGggPSA2LCBoZWlnaHQgPSA3LjUpCmBgYAoqKkZpZy4gPyoqIEJsdWUgYm94ZXMgaW5kaWNhdGUgdGhlIFBGMTE3NjUgZG9tYWlucyB3aGlsZSBhbGwgb3RoZXIgbm9uLWdyZXkgYm94ZXMgaW5kaWNhdGUgWFNUUkVBTS1kZXRlcm1pbmVkIHRhbmRlbSByZXBlYXQgZG9tYWlucy4gQ29sb3JzIGFyZSB1c2VkIHRvIGdyb3VwIGhpZ2hseSBzaW1pbGFyIHRhbmRlbSByZXBlYXRzLiBUaGUgYmxhY2sgdGhpbiBsaW5lcyBkZW1hcmNhdGUgYWRqYWNlbnQgdGFuZGVtIHJlcGVhdCB1bml0cy4gVGhlIHRhYmxlIGJlbG93IHNob3dzIHRoZSBjb3B5IG51bWJlciwgcGVyaW9kIGFuZCBjb25zZW5zdXMgc2VxdWVuY2UgZm9yIGVhY2ggdGFuZGVtIGRvbWFpbiBvcmdhbml6ZWQgYnkgdGhlIGhvc3Qgc2VxdWVuY2VzLgoKIyMgU2VwYXJhdGUgVFIgdHlwZXMKCmBgYHtyfQojRFQ6OmRhdGF0YWJsZSgKIyAgdGFuZGVtICU+JSAKIyAgICBkcGx5cjo6cmVuYW1lKHNlcUwgPSBzZXFMZW5ndGgsIGVyciA9IGNvbnNlbnN1c19lcnJvciwgc2VxID0gY29uc2Vuc3VzX25vZ2FwKSAlPiUgCiMgICAgc2VsZWN0KC1zZXFBbGlnbiwgLXR5cGUsIC1jb25zZW5zdXNfZ2FwLCAtc2VxLCBzZXEpICU+JSAKIyAgICBhcnJhbmdlKGRlc2MobmFtZSkpLAojICBmaWxsQ29udGFpbmVyID0gRkFMU0UsIG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSAxMCkKIykKYGBgCgpSZXBlYXQgdGhlIGFib3ZlIGFuYWx5c2lzIGJ1dCBkaXN0aW5ndWlzaGluZyBiZXR3ZWVuIGFsbCBkaWZmZXJlbnQgVFIgdHlwZXMKYGBge3Igc2V0X3RyX2NvbG9yfQpyZXF1aXJlKFJDb2xvckJyZXdlcikKdHIudGggPC0gMTAwICMgYXJiaXRyYXJ5IHRocmVzaG9sZCBmb3IgZGlzdGluZ3Vpc2hpbmcgInNob3J0IiBmcm9tICJsb25nIiBUUnMKdHIuY29sIDwtIGNoYXJhY3Rlcihucm93KHJlcGVhdHMpKSAjIGNyZWF0ZSBhIGNvbG9yIHZlY3RvcgpzaG9ydC5ycCA8LSB3aGljaChyZXBlYXRzJGxlbmd0aCA8IHRyLnRoKSAjIGlkZW50aWZ5IHRoZSBzaG9ydCByZXBlYXRzIGluZGljZXMKbG9uZy5ycCA8LSBzZXRkaWZmKDE6bnJvdyhyZXBlYXRzKSwgc2hvcnQucnApICMgdGhlIGxvbmcgcmVwZWF0cyBpbmRpY2VzCnNldC5zZWVkKDEyMykgIyBmb3IgcmVwcm9kdWNpYmx5IHNodWZmbGluZyB0aGUgb3JkZXIgYmVmb3JlIGFzc2lnbmluZyB0aGUgY29sb3JzCnNob3J0LnJwIDwtIHNhbXBsZShzaG9ydC5ycCkgIyBzaHVmZmxlIHRoZSBpbmRpY2VzIGZvciBzaG9ydCB0YW5kZW0gcmVwZWF0cwp0ci5jb2xbc2hvcnQucnBdIDwtIGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbCgxMiwgIlBhaXJlZCIpW3NlcSgzLDExLGJ5PTIpXSkobGVuZ3RoKHNob3J0LnJwKSkgIyBhc3NpZ24gdGhlIHNob3J0IHJlcGVhdHMgYSBsb3dlciBjb250cmFzdCBjb2xvcgpzZXQuc2VlZCgyMzEpICMgZm9yIHJlcHJvZHVjaWJseSBzaHVmZmxpbmcgdGhlIG9yZGVyIGJlZm9yZSBhc3NpZ25pbmcgdGhlIGNvbG9ycwpsb25nLnJwIDwtIHNhbXBsZShsb25nLnJwKQp0ci5jb2xbbG9uZy5ycF0gPC0gY29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKDEyLCAiUGFpcmVkIilbc2VxKDQsMTIsYnk9MildKShsZW5ndGgobG9uZy5ycCkpICMgYXNzaWduIHRoZSBsb25nIHJlcGVhdHMgYSBoaWdoZXIgY29udHJhc3QgY29sb3IKIyAtLSBkZXNhdHVyYXRlIHRoZSBjb2xvcnMgLS0gCiMgaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMjYzMTQ3MDEvci1yZWR1Y2luZy1jb2xvdXItc2F0dXJhdGlvbi1vZi1hLWNvbG91ci1wYWxldHRlCmxpYnJhcnkoY29sb3JzcGFjZSkgICAjIyBoc3YgY29sb3JzcGFjZSBtYW5pcHVsYXRpb25zCgojIyBGdW5jdGlvbiBmb3IgZGVzYXR1cmF0aW5nIGNvbG9ycyBieSBzcGVjaWZpZWQgcHJvcG9ydGlvbgpkZXNhdCA8LSBmdW5jdGlvbihjb2xzLCBzYXQ9MC41KSB7CiAgICBYIDwtIGRpYWcoYygxLCBzYXQsIDEpKSAlKiUgcmdiMmhzdihjb2wycmdiKGNvbHMpKQogICAgaHN2KFhbMSxdLCBYWzIsXSwgWFszLF0pCn0KCnRyLmNvbCA8LSBkZXNhdCh0ci5jb2wsIHNhdCA9IDAuOCkKIyAtLSBmaW5pc2ggLS0KdHIuY29sIDwtIHBhc3RlMCh0ci5jb2wsICJDQyIpICMgYWRkIDIwJSB0cmFuc3BhcmVuY3kgdG8gdGhlIFRSIGZlYXR1cmVzCm5hbWVzKHRyLmNvbCkgPC0gcGFzdGUwKCJUUi0iLCByZXBlYXRzJHR5cGUpICMgbmFtZSB0aGUgY29sb3JzIGJ5IHRoZSBUUiB0eXBlcwpyZXBlYXRzJGNvbG9yIDwtIHRyLmNvbApgYGAKCkNvbWJpbmUgZG9tYWlucywgU1AgYW5kIEdQSS1hbmNob3Igd2l0aCBUUiBmZWF0dXJlcy4KYGBge3J9IAojIGNvbWJpbmUgc2VxdWVuY2UgZmVhdHVyZXMgd2l0aCB0YW5kZW0gcmVwZWF0cwpmZWF0dXJlMSA8LSBiaW5kX3Jvd3MoZmlsdGVyKGZlYXR1cmUsIHR5cGUgIT0gIlRhbmRlbSBSZXBlYXRzIiksIHRyKSAlPiUgCiAgbXV0YXRlKHR5cGUgPSBvcmRlcmVkKHR5cGUsIGxldmVscyA9IGMoIkh5cGhhbF9yZWdfQ1dQIiwgIlNpZ25hbFAiLCAiR1BJLWFuY2hvciIsIHVuaXF1ZSh0ciR0eXBlKSkpKQpmZWF0dXJlLmNvbDEgPC0gYyhmZWF0dXJlLmNvbG9yc1sxOjNdLCB0ci5jb2wpICMgcmVtb3ZlIHRoZSBzaW5nZWwgIlRhbmRlbSBSZXBlYXRzIiB0eXBlCiN3cml0ZV90c3YoZmVhdHVyZTEsIGZpbGUgPSAiLi4vb3V0cHV0L21pc2MvUi1mZWF0dXJlLXRhYmxlLnRzdiIsIGNvbF9uYW1lcyA9IFRSVUUpCmBgYAoKYGBge3IsIHdhcm5pbmc9RkFMU0V9CiMgcGxvdApwMSA8LSBnZW9tX3NlZ21lbnQoZGF0YSA9IGZlYXR1cmUxLCBhZXMoY29sb3IgPSB0eXBlLCB0ZXh0ID0gdGlwKSwgc2l6ZSA9IGgpCnAyIDwtIGdlb21fc2VnbWVudChkYXRhID0gdGFuZGVtLmRpdiwgYWVzKHggPSBuYW1lLCB4ZW5kID0gbmFtZSwgeSA9IGRpdiwgeWVuZCA9IGRpdiArIDEuNSksCiAgICAgICAgICAgICAgICAgICBzaXplID0gaCwgY29sb3IgPSAid2hpdGUiKQpwMyA8LSBwMCArIHAxICsgY29vcmRfZmxpcCgpICsgdGhlbWVfY2xhc3NpYygpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGZlYXR1cmUuY29sMSkgKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMC4wMiwgMC4wMikpKSArCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMpLCBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy5saW5lLnkgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLmxpbmUueCA9IGVsZW1lbnRfYmxhbmsoKSwjIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9IGFscGhhKCJsaWdodGJsdWUiLDAuMSkpKSArCiAgbGFicyh5ID0gIlBvc2l0aW9uIGluIHNlcXVlbmNlIiwgeCA9ICJTZXF1ZW5jZXMiLCBjb2xvciA9ICJGRUFUVVJFUyIpCiMgcGxvdF9ncmlkKHAuZ3RyZWUsIHAzICsgcDIsIG5jb2wgPSAyLCBhbGlnbiA9ICd2JywgcmVsX3dpZHRocyA9IGMoMSwyKSwgc2NhbGUgPSBjKDEuMDEsMSkpCmdnc2F2ZSgiLi4vb3V0cHV0L2ltZy8yMDIyMDkxNi1kb21haW4tdGFuZGVtLXJlcGVhdHMtZGlzdGluY3QtY29sb3IucG5nIiwgcGxvdCA9IHAzLCB3aWR0aCA9IDUsIGhlaWdodCA9IDcuNSkKYGBgCgpgYGB7ciwgd2FybmluZz1GQUxTRSwgZmlnLmhlaWdodD05LCBmaWcud2lkdGg9OX0KIyBwbG90CiNyZXF1aXJlKHBsb3RseSkKcGxvdGx5OjpnZ3Bsb3RseShwMywgdG9vbHRpcCA9ICJ0ZXh0Iiwgd2lkdGggPSA5MDAsIGhlaWdodCA9IDkwMCkKYGBgCgojIyBUYW5nbyBwcmVkaWN0ZWQgzrItYWdncmVnYXRpb24gc2VxdWVuY2VzCmBgYHtyIHRhbmdvX3NlcXVlbmNlcywgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9OH0KIyByZW9yZGVyIHRoZSBzZXF1ZW5jZXMgZm9yIHBsb3R0aW5nCiMgcGxvdAojcDEgPC0gZ2dwbG90KHNlcUxlbiwgYWVzKHggPSBuYW1lLCB5ID0gc3RhcnQsIHhlbmQgPSBuYW1lLCB5ZW5kID0gZW5kKSkgKyBnZW9tX3NlZ21lbnQoY29sb3IgPSAiZ3JheTgwIiwgc2l6ZSA9IDIpCnAxIDwtIGdlb21fc2VnbWVudChkYXRhID0gZmlsdGVyKHBmMTE3NjUsICFuYW1lICVpbiUgTWIucm0kbmFtZSksIAogICAgICAgICAgICAgICAgICAgYWVzKHggPSBuYW1lLCB4ZW5kID0gbmFtZSwgeSA9IHN0YXJ0KzEsIHllbmQgPSBlbmQpLCBzaXplID0gaCwgY29sb3IgPSAiIzNkODRjNiIpCnAyIDwtIGdlb21fc2VnbWVudChkYXRhID0gZmlsdGVyKHRhbmdvLCAhbmFtZSAlaW4lIE1iLnJtJG5hbWUpLCAKICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gbmFtZSwgeGVuZCA9IG5hbWUsIHkgPSBpZmVsc2Uoc3RhcnQtNCA+PSAwLCBzdGFydC00LCAwKSwgeWVuZCA9IGVuZCArIDQsIGNvbG9yID0gbWVkaWFuKSwgc2l6ZSA9IGgpCnAzIDwtIHAwICsgcDEgKyBwMiArIGNvb3JkX2ZsaXAoKSArIHRoZW1lX2NsYXNzaWMoKSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYyhsaW1pdHMgPSBjKDUsMTAxKSwgYnJlYWtzID0gYyg1LHNlcSgyNSwxMDAsMjUpKSwgZGlyZWN0aW9uID0gLTEpICsKICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNCksIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLmxpbmUueSA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMubGluZS54ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gYygwLjgsMC44OCksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBhbHBoYSgibGlnaHRibHVlIiwwLjEpKSkgKwogIHlsaW0oLTIsIDQ1MDApICsgbGFicyh5ID0gIlBvc2l0aW9uIGluIHNlcXVlbmNlIiwgeCA9ICJTZXF1ZW5jZXMiLCBjb2xvciA9ICJUQU5HTyBzY29yZSIpCnAzCiMjcGxvdF9ncmlkKHAuZ3RyZWUsIHA0LCBuY29sID0gMiwgYWxpZ24gPSAndicsIHJlbF93aWR0aHMgPSBjKDEsMi41KSwgc2NhbGUgPSBjKDEuMDEsMSkpCmdnc2F2ZSgiLi4vb3V0cHV0L2ltZy8yMDIyMDkxNi10YW5nby1zY29yZS1zZWdtZW50LnBuZyIsIHBsb3QgPSBwMywgd2lkdGggPSA2LCBoZWlnaHQgPSA3LjUpCmBgYAoKVG8gY29tcGFyZSB0aGUgbnVtYmVyIG9mIFRBTkdPIG1vdGlmcyBpbiBfQy4gYXVyaXNfIEhpbDEtNCBhbmQgdGhlaXIgY2xvc2UgaG9tb2xvZ3MgdG8gdGhlIHJlc3Qgb2YgdGhlIEhpbCBmYW1pbHksIHdlIGZpcnN0IGlkZW50aWZ5IHRoZSBmaXJzdCBncm91cCBvZiBzZXF1ZW5jZXMKYGBge3J9CmEgPC0gd2hpY2goZ2VuZXRyZWVPcmRlciA9PSAiWFBfMDI1MzQ0NDE2LjFfQ2FuZGlkYV9oYWVtdWxvbmkiLCBhcnIuaW5kID0gVFJVRSkKYiA8LSB3aGljaChnZW5ldHJlZU9yZGVyID09ICJYUF8wMjQ3MTYzNjUuMV9DYW5kaWRhX3BzZXVkb2hhZW11bG9uaWkiLCBhcnIuaW5kID0gVFJVRSkKaGlsMV80X21kciA8LSBnZW5ldHJlZU9yZGVyW2E6Yl0Kcm0obGlzdCA9IGMoImEiLCAiYiIpKQpgYGAKCmBgYHtyfQptb3RpZi5wZXIuc2VxICU+JSAKICBzZWxlY3QobmFtZSwgbi5hbGwpICU+JSAKICBtdXRhdGUoZ3JvdXAgPSBpZmVsc2UobmFtZSAlaW4lIGhpbDFfNF9tZHIsICJIaWwxLTRfTURSIiwgIm90aGVycyIpKSAlPiUgCiAgZ3JvdXBfYnkoZ3JvdXApICU+JSAKICBzdW1tYXJpemUobWVkaWFuID0gbWVkaWFuKG4uYWxsKSkKYGBgCgoKXyoqRGlzY3Vzc2lvbioqXwoKLSBUaGUgb25lIHNlcXVlbmNlIGJlbG93IDUwMCBhLmEuIGlzIGZyb20gX04uIGRlbHBoZW5zaXNfLCB3aGljaCBpcyBsYWJlbGVkIGFzIGEgcGFydGlhbCBDRFMuCi0gTWFqb3JpdHkgb2YgdGhlIHByb3RlaW5zIGluIHRoZSBsaXN0IGFyZSA1MDAtMjAwMCBhLmEuLCB3aXRoIGEgZmV3IGV4Y2VwdGlvbmFsbHkgbG9uZwotIE5vdCBvbmx5IGRvIFNhY2NoYXJvbXljZXRhY2VhZSBzcGVjaWVzIGhhdmUgZmV3ZXIgSGlsIGZhbWlseSBob21vbG9ncywgdGhlIG9uZXMgdGhleSBoYXZlIGFyZSBhbHNvIHNob3J0ICg8IDEwMDAgYS5hLikgd2l0aCB0aGUgZXhjZXB0aW9uIG9mIF9DLiBnbGFicmF0YV8KCgoKIyBDaHJvbW9zb21hbCBsb2NhdGlvbnMKCiMjIEFyZSBtZW1iZXJzIG9mIHRoaXMgcHJvdGVpbiBmYW1pbHkgZW5yaWNoZWQgaW4gdGhlIHN1YnRlbG9tZXJpYyByZWdpb25zPwpBIHJlY2VudCBsb25nLXJlYWQgc2VxdWVuY2luZyBzdHVkeSBmb3IgX0MuIGdsYWJyYXRhXyBhbm5vdGF0ZWQgMzEgbm92ZWwgT1JGcywgb2Ygd2hpY2ggMjQgYXJlIEdQSS1DZWxsIFdhbGwgUHJvdGVpbnMuIFRoZSBhdXRob3JzIGNpdGVkIHByZXZpb3VzIGxpdGVyYXR1cmUgc3VwcG9ydGluZyB0aGUgIGluIHRoZSBzdWJ0ZWxvbWVyaWMgcmVnaW9ucyBbWHUgMjAyMF0oaHR0cHM6Ly9kb2kub3JnLzEwLjExMTEvbW1pLjE0NDg4KS4gV2hpbGUgcGVyZm9ybWluZyBCTEFTVCBvbiBGdW5naURCIHRvIGlkZW50aWZ5IGhvbW9sb2dzIG9mIG91ciBwcm90ZWluLCBJIGFsc28gbm90aWNlZCB0aGF0IG1hbnkgb2YgdGhlIGhpdHMgYXBwZWFyIHRvIGJlIGF0IHRoZSBiZWdpbm5pbmcgYW5kIGVuZCBvZiB0aGUgY2hyb21vc29tZXMuCgpUbyB0ZXN0IGlmIHRoZXJlIGlzIGluZGVlZCBhIHNpZ25pZmljYW50IGVucmljaG1lbnQgYW1vbmcgdGhpcyBmYW1pbHkgb2YgcHJvdGVpbnMgaW4gdGhlIHN1YnRlbG9tZXJpYyByZWdpb25zLCBJIGNvbGxlY3RlZCB0aGUgY2hyb21vc29tYWwgbG9jYXRpb25zIGZvciBhIHN1YnNldCBvZiB0aGUgc3BlY2llcyB3aG9zZSBnZW5vbWVzIHdlcmUgYXNzZW1ibGVkIHRvIGEgY2hyb21vc29tYWwgb3IgY29tcGxldGUgZ2Vub21lIGxldmVsICh0aGUgdHdvIGFyZSBzb21ld2hhdCBlcXVpdmFsZW50KS4gVGhlc2UgaW5jbHVkZSBfQ2FuZGlkYSBhbGJpY2FucywgQ2FuZGlkYSBhdXJpcywgQ2FuZGlkYSBkdWJsaW5pZW5zaXMsIENhbmRpZGEgb3J0aG9wc2lsb3NpcywgRGViYXJ5b215Y2VzIGhhbnNlbmlpLCBLYXphY2hzdGFuaWEgYWZyaWNhbmEsIEthemFjaHN0YW5pYSBuYWdhbmlzaGlpLCBLbHV5dmVyb215Y2VzIGxhY3RpcywgTmF1bW92b3p5bWEgY2FzdGVsbGlpLCBOYXVtb3ZvenltYSBkYWlyZW5lbnNpcywgQ2FuZGlkYSBnbGFicmF0YSwgU2NoZWZmZXJzb215Y2VzIHN0aXBpdGlzXwoKVG8gZm9ybWFsbHkgdGVzdCB0aGlzIGh5cG90aGVzaXMsIEkgbmVlZCB0byBhY2NvdW50IGZvciB0aGUgYmFja2dyb3VuZCBnZW5lIGRlbnNpdHkgZGlmZmVyZW5jZXMgYWxvbmcgdGhlIGNocm9tb3NvbWVzLiBUaGUgaWRlYSBpcyB0byBjb21wYXJlIHRoZSBjaHJvbW9zb21hbCBwb3NpdGlvbnMgZm9yIHRoaXMgZ3JvdXAgb2YgcHJvdGVpbnMgY29tcGFyZWQgd2l0aCB0aGUgZ2VuZSBkZW5zaXRpZXMgb24gdGhlIGNocm9tb3NvbWVzIHRoZXkgcmVzaWRlIG9uLgoKT25lIGNvbnNpZGVyYXRpb24gZm9yIHRoaXMgYW5hbHlzaXMgaXMgdGhhdCBpZiB3ZSBzaW1wbHkgdXNlIGFsbCB0aGUgc3BlY2llcyBmb3Igd2hpY2ggYSB3ZWxsIGFzc2VtYmxlZCBnZW5vbWUgaXMgYXZhaWxhYmxlLCB3ZSBtYXkgZW5kIHVwIG92ZXItc2FtcGxpbmcgYSBwaHlsb2dlbmV0aWMgY2xhZGUgYW5kIGhhdmluZyBpdHMgSGlsIGZhbWlseSdzIGxvY2FsaXphdGlvbiBvdmVyLXdlaWdodGVkIGluIHRoZSBmaW5hbCB0ZXN0LiBUbyBhdm9pZCBnaXZpbmcgdG9vIG11Y2ggd2VpZ2h0IG9uIGEgZ3JvdXAgb2Ygc3BlY2llcywgSSB3aWxsIHNlbGVjdCBhIHJlcHJlc2VudGF0aXZlIHNwZWNpZXMgaWYgbW9yZSB0aGFuIG9uZSBpcyBhdmFpbGFibGUgaW4gYSByZWxhdGl2ZWx5IGNsb3NlbHkgcmVsYXRlZCBjbGFkZS4gRm9yIGV4YW1wbGUsIHdlIHdpbGwgdXNlIF9DYW5kaWRhIGFsYmljYW5zXyBhbmQgcmVtb3ZlIF9DYW5kaWRhIGR1YmxpbmllbnNpc18uCgpgYGB7ciBkZWNpZGVfd2hpY2hfc3BlY2llc190b191c2V9CiMgaW1wb3J0IHRoZSBjaHJvbW9zb21hbCBsb2NhdGlvbiBpbmZvcm1hdGlvbgpjaHJMb2MgPC0gcmVhZF90c3YoIi4uL2RhdGEvMjAyMjA5MTktZXhwYW5kZWQtYmxhc3QtY2hyb21vc29tYWwtbG9jYXRpb25zLnRzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkKIyBkZWNpZGUgdGhlIHNwZWNpZXMgdG8gYmUgdXNlZCBmb3IgdGhlIGFuYWx5c2lzCnVzZS5zcHMgPC0gYygiQ2FuZGlkYSBhbGJpY2FucyIsICJEZWJhcnlvbXljZXMgaGFuc2VuaWkiLCAiQ2FuZGlkYSBvcnRob3BzaWxvc2lzIiwKICAgICAgICAgICAgICJLYXphY2hzdGFuaWEgYWZyaWNhbmEiLCAiS2x1eXZlcm9teWNlcyBsYWN0aXMiLAogICAgICAgICAgICAgIk5hdW1vdm96eW1hIGRhaXJlbmVuc2lzIiwgIkNhbmRpZGEgYXVyaXMiLCAiQ2FuZGlkYSBnbGFicmF0YSIpCiMgY3JlYXRlIGEgbmV3IHRpYmJsZSBmb3Igb3VyIGhvbW9sb2dzIGZyb20gdGhlc2Ugc3BlY2llcwpmZy5mcmVxIDwtIGNockxvYyAlPiUgZmlsdGVyKHNwZWNpZXMgJWluJSB1c2Uuc3BzKQojIGltcG9ydCBhc3NlbWJseSBpbmZvCmFzc2VtYmx5LmluZm8gPC0gcmVhZF90c3YoIi4uL2RhdGEvMjAyMjA1MjUtZXhwYW5kZWQtYmxhc3Qtc3BlY2llcy1hc3NlbWJseS1pbmZvLnRzdiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29sX3R5cGVzID0gY29scygpKQp1c2Uuc3BzIDwtIGFzc2VtYmx5LmluZm8gJT4lIAogIGZpbHRlcihzcGVjaWVzICVpbiUgdXNlLnNwcykgJT4lCiAgZmlsdGVyKCFzcGVjaWVzICVpbiUgYygiQ2FuZGlkYSBnbGFicmF0YSIsICJDYW5kaWRhIGF1cmlzIiwgIktsdXl2ZXJvbXljZXMgbGFjdGlzIikpICU+JSAKICBzZWxlY3Qoc3BlY2llcywgYXNzZW1ibHkgPSBhc3NlbWJseWFjY2Vzc2lvbikgJT4lIAogICMgbWFudWFsbHkgYWRkIHNldmVyYWwgc3BlY2llcy4gbm90ZSB0aGF0IHdlIGFyZSB1c2luZyB0aGUgQjExMjQ1IChDbGFkZSA0KSBzdHJhaW4gdG8gCiAgIyByZXByZXNlbnQgQy4gYXVyaXMsIGJlY2F1c2UgaXQgaXMgYXNzZW1ibGVkIHRvIGEgY2hyb21vc29tZSBsZXZlbCBhbmQgaGFzIGFubm90YXRpb24gZmlsZXMKICBhZGRfcm93KHNwZWNpZXMgPSBjKCJDYW5kaWRhIGdsYWJyYXRhIiwgIkNhbmRpZGEgYXVyaXMiLCAiS2x1eXZlcm9teWNlcyBsYWN0aXMiKSwKICAgICAgICAgIGFzc2VtYmx5ID0gYygiR0NBXzAxMDExMTc1NS4xIiwgIkdDQV8wMDgyNzUxNDUuMSIsICJHQ0ZfMDAwMDAyNTE1LjIiKSkKYGBgCgpUbyBjb25kdWN0IHRoaXMgdGVzdCwgd2UgZmlyc3QgbmVlZCB0byBwcmVwYXJlIGFuZCBjb21wdXRlIHRoZSBiYWNrZ3JvdW5kIGdlbmUgZGVuc2l0aWVzLiBUbyBkbyB0aGlzLCB3ZSB3aWxsIGdhdGhlciB0aGUgZ2Vub21lIGFzc2VtYmx5IGZpbGVzIGZvciB0aGUgc2VsZWN0ZWQgc3BlY2llcywgcmVhZCB0aGVtIGludG8gUiwgYW5kIGdlbmVyYXRlIGEgdGFibGUgdGhhdCBjb250YWlucyBvbmUgcm93IGZvciBlYWNoIGdlbmUsIHdpdGggaXRzIGdlbmUgSUQsIGNocm9tb3NvbWUgbnVtYmVyLCBjaHJvbW9zb21lIGxlbmd0aCBhbmQgdGhlIHN0YXJ0IHBvc2l0aW9uIGV4cHJlc3NlZCBhcyBhIHBlcmNlbnRhZ2UgbWVhc3VyZWQgZnJvbSB0aGUgY2hyb21vc29tZSBlbmRzLgoKYGBge3IgY29tcHV0ZV9iYWNrZ3JvdW5kX2ZyZXF9CiMgMS4gcHJlcGFyZSBmaWxlIG5hbWVzCiMgICBnZXQgYWxsIGZpbGUgbmFtZXMgdGhhdCBlbmRzIHdpdGggImZlYXR1cmVfdGFibGUudHh0Lmd6Iiwgd2hpY2ggY29udGFpbiB0aGUgZ2VuZSBhbm5vdGF0aW9uCmZlYXR1cmUuZmlsZXMgPC0gbGlzdC5maWxlcyhwYXRoID0gIi4uL2RhdGEvYXNzZW1ibHktaW5mby8iLCBwYXR0ZXJuID0gIipmZWF0dXJlX3RhYmxlLnR4dC5neiQiKQpuYW1lcyhmZWF0dXJlLmZpbGVzKSA8LSBzYXBwbHkoc3RyX3NwbGl0KGZlYXR1cmUuZmlsZXMsIHBhdHRlcm4gPSAiXyIpLCBmdW5jdGlvbih4KSB7CiAgcGFzdGUoeFsxXSwgeFsyXSwgc2VwID0gIl8iKQp9KQojIGdldCBhbGwgZmlsZSBuYW1lcyB0aGF0IGVuZHMgd2l0aCAiYXNzZW1ibHlfcmVwb3J0LnR4dCIsIHdoaWNoIGNvbnRhaW4gdGhlIGNocm9tb3NvbWFsIGxlbmd0aAphc3NlbWJseS5maWxlcyA8LSBsaXN0LmZpbGVzKHBhdGggPSAiLi4vZGF0YS9hc3NlbWJseS1pbmZvLyIsIHBhdHRlcm4gPSAiKmFzc2VtYmx5X3JlcG9ydC50eHQkIikKbmFtZXMoYXNzZW1ibHkuZmlsZXMpIDwtIHNhcHBseShzdHJfc3BsaXQoYXNzZW1ibHkuZmlsZXMsIHBhdHRlcm4gPSAiXyIpLCBmdW5jdGlvbih4KSB7CiAgcGFzdGUoeFsxXSwgeFsyXSwgc2VwID0gIl8iKQp9KQp1c2Uuc3BzJEZlYXR1cmVGaWxlIDwtIGZlYXR1cmUuZmlsZXNbdXNlLnNwcyRhc3NlbWJseV0KdXNlLnNwcyRBc3NlbWJseUZpbGUgPC0gYXNzZW1ibHkuZmlsZXNbdXNlLnNwcyRhc3NlbWJseV0KYGBgCgpgYGB7cn0KIyAyLiByZWFkIGluIHRoZSBhc3NlbWJseSBpbmZvcm1hdGlvbgpmZWF0dXJlLmNvbC5uYW1lcyA8LSBjKCJmZWF0dXJlIiwiY2xhc3MiLCJhc3NlbWJseSIsImFzc2VtYmx5X3VuaXQiLCJzZXFfdHlwZSIsImNocm9tb3NvbWUiLCJnZW5vbWljX2FjY2Vzc2lvbiIsInN0YXJ0IiwiZW5kIiwic3RyYW5kIiwicHJvZHVjdF9hY2Nlc3Npb24iLCJub25fcmVkdW5kYW50X3JlZnNlcSIsInJlbGF0ZWRfYWNjZXNzaW9uIiwibmFtZSIsInN5bWJvbCIsIkdlbmVJRCIsImxvY3VzX3RhZyIsImZlYXR1cmVfaW50ZXJ2YWxfbGVuZ3RoIiwicHJvZHVjdF9sZW5ndGgiLCJhdHRyaWJ1dGVzIikKYXNzZW1ibHkuY29sLm5hbWVzIDwtIGMoImNocm9tb3NvbWUiLCJzZXFfcm9sZSIsImFzc2lnbl9tb2xlY3VsZSIsInR5cGUiLCJnYl9hY2MiLCJyZWxhdGlvbnNoaXAiLAogICAgICAgICAgICAgICAgICAgICAgICAicmVmc2VxX2FjYyIsImFzc2VtYmx5X3VuaXQiLCJzZXFMIiwidWNzY19uYW1lIikKY29tcHV0ZS5iZy5mcmVxIDwtIGZ1bmN0aW9uKHJvdyl7CiAgYXNzZW1ibHkuZmlsZSA8LSByb3dbIkFzc2VtYmx5RmlsZSJdCiAgYXNzZW1ibHkgPC0gcmVhZF90c3YocGFzdGUwKCIuLi9kYXRhL2Fzc2VtYmx5LWluZm8vIixhc3NlbWJseS5maWxlKSwgY29tbWVudCA9ICIjIiwKICAgICAgICAgICAgICAgICAgICAgICBjb2xfbmFtZXMgPSBhc3NlbWJseS5jb2wubmFtZXMsIGNvbF90eXBlcyA9ICJjY2NjY2NjY2ljIikKICBmZWF0dXJlLmZpbGUgPC0gcm93WyJGZWF0dXJlRmlsZSJdCiAgZmVhdHVyZSA8LSByZWFkX3RzdihwYXN0ZTAoIi4uL2RhdGEvYXNzZW1ibHktaW5mby8iLGZlYXR1cmUuZmlsZSksIGNvbF9uYW1lcyA9IGZlYXR1cmUuY29sLm5hbWVzLAogICAgICAgICAgICAgICAgICAgICAgY29sX3R5cGVzID0gImNjY2NjY2NpaWNjY2NjY2NjaWljIiwgc2tpcCA9IDEpCiAgcmVzIDwtIGZlYXR1cmUgJT4lIAogICAgZmlsdGVyKGZlYXR1cmUgPT0gIm1STkEiKSAlPiUgCiAgICAjIHRoZXNlIGZlYXR1cmUgdGFibGVzIGFyZSBvcmdhbml6ZWQgaGllcmFyY2hpY2FsbHksIHdpdGggdGhlIHRvcCBsZXZlbCBiZWluZyAiZ2VuZSIKICAgICMgdGhlIG5leHQgbGV2ZWwgb25lIG9mICJtUk5BIiwgIm5jUk5BIiwgInRSTkEiIG9yICJyUk5BIi4gd2Ugb25seSBjb3VudCBwcm90ZWluLWNvZGluZyBnZW5lcywgaS5lLgogICAgIyAibVJOQSIuIHRoZSByZWFzb24gSSBkaWRuJ3Qgc2VsZWN0IHRoZSAiQ0RTIiBmZWF0dXJlIHR5cGUgaXMgYmVjYXVzZSBpbiBhIHNtYWxsIG51bWJlciBvZiBjYXNlcywKICAgICMgb25lIG1STkEgZmVhdHVyZSBjb250YWlucyBtb3JlIHRoYW4gb25lIENEUyBmZWF0dXJlLCBwb3NzaWJseSBkdWUgdG8gc3BsaWNpbmcgb3IgYWx0ZXJuYXRpdmUgCiAgICAjIHRyYW5zbGF0aW9uYWwgc3RhcnQgc2l0ZQogICAgc2VsZWN0KGNocm9tb3NvbWUsIHN0YXJ0LCBlbmQpICU+JSAKICAgIGxlZnRfam9pbihhc3NlbWJseSAlPiUKICAgICAgICAgICAgICAgIG11dGF0ZShjaHJhY2N2ZXIgPSBpZmVsc2UocmVmc2VxX2FjYyAhPSAibmEiLCByZWZzZXFfYWNjLCBnYl9hY2MpKSAlPiUgCiAgICAgICAgICAgICAgICBzZWxlY3QoY2hyb21vc29tZSwgY2hyYWNjdmVyLCBzZXFMKSwgCiAgICAgICAgICAgICAgYnkgPSBjKCJjaHJvbW9zb21lIiA9ICJjaHJvbW9zb21lIikpICU+JQogICAgbXV0YXRlKHJlbExvYyA9IHJvdW5kKHN0YXJ0IC8gc2VxTCwgMykpCiAgcmV0dXJuKHJlcykKfQpgYGAKCmBgYHtyfQojIDMuIGFwcGx5IHRoZSBmdW5jdGlvbiB0byB0aGUgZ2Vub21lcwpiZy5mcmVxIDwtIGFwcGx5KHVzZS5zcHMsIE1BUkdJTiA9IDEsIGNvbXB1dGUuYmcuZnJlcSkKbmFtZXMoYmcuZnJlcSkgPC0gdXNlLnNwcyRzcGVjaWVzCmBgYAoKTGV0J3MgdGFrZSBhIGxvb2sgYXQgdGhlIGdlbmUgZGVuc2l0eSBpbiBvbmUgb2YgdGhlIGdlbm9tZXMsIGUuZy4gX0QuIGhhbnNlbmlpXwoKQmVsb3cgSSB1c2UgdGhlIGBnZW9tX2hpc3RvZ3JhbWAgZnVuY3Rpb24gaW5zdGVhZCwgd2l0aCBicmVha3Mgc3BlY2lmaWVkIG1hbnVhbGx5LiBUaGlzIHJlc3VsdHMgaW4gYSBkZW5zaXR5IGRpc3RyaWJ1dGlvbiB0aGF0IGlzIHByZXR0eSBmbGF0IGFjcm9zcyB0aGUgY2hyb21vc29tZXMuCmBgYHtyfQpiZy5mcmVxJGBEZWJhcnlvbXljZXMgaGFuc2VuaWlgICU+JSBnZ3Bsb3QoYWVzKHggPSByZWxMb2MpKSArIAogIGdlb21faGlzdG9ncmFtKGJyZWFrcyA9IHNlcSgwLDEsMC4wNSkpICsKICBmYWNldF93cmFwKH4gY2hyb21vc29tZSkgKyBnZ3RpdGxlKCJELiBoYW5zZW5paSIpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpCmBgYAoKSW4gb3JkZXIgdG8gY29tcGFyZSB0aGUgZGlzdHJpYnV0aW9uIG9mIF9hbGxfIGdlbmVzIGluIGRpZmZlcmVudCBiaW5zIG9mIHRoZSBjaHJvbW9zb21lcyB0byB0aGUgaG9tb2xvZ3MgaW4gb3VyIGNhc2Ugc3R1ZHksIHdlIGNhbiBkaXZpZGUgZWFjaCBjaHJvbW9zb21lIGluIHRoZSBgbnJvdyh1c2Uuc3BzKWAgZ2Vub21lcyBpbnRvIGFuIGFyYml0cmFyeSBudW1iZXIgb2YgYmlucyBhZnRlciAiZm9sZGluZyIgdGhlbSBpbiBoYWxmLCBlLmcuIDAtMTAlLCAxMC0yMCUsIDIwLTMwJSwgMzAtNDAlIGFuZCA0MC01MCUuIFRvIGJlIGFibGUgdG8gdmlzdWFsbHkgY29tcGFyZSB0aGUgZGlzdHJpYnV0aW9uIG9mIG91ciBob21vbG9ncyBhbmQgdGhlIGdlbm9tZSBiYWNrZ3JvdW5kLCB3ZSB3aWxsIGNyZWF0ZSBhIHNwZWNpYWwgImNocm9tb3NvbWUiIGNsYXNzIHRoYXQgd2lsbCBiZSBvdXIgaG9tb2xvZ3MgYW5kIGNvbWJpbmUgdGhlbSB3aXRoIHRoZSBgYmcuZnJlcWAgdGFibGUuCmBgYHtyfQpmcmVxLmJpbnMgPC0gYygtMC4wMDEsIHNlcSgwLjEsIDAuNSwgMC4xKSk7IGZyZXEuYmluc0wgPC0gYygwLCBmcmVxLmJpbnNbLTFdKQpmcmVxLmxhYmVsIDwtIHBhc3RlMChoZWFkKGZyZXEuYmluc0wsIC0xKSoxMDAsIi0iLHRhaWwoZnJlcS5iaW5zTCwgLTEpKjEwMCwiJSIpCmJnLmZyZXEudGIgPC0gYmluZF9yb3dzKGJnLmZyZXEsIC5pZCA9ICJzcGVjaWVzIikgJT4lIAogIG11dGF0ZShmb2xkLnJlbExvYyA9IGlmZWxzZShyZWxMb2MgPD0gMC41LCByZWxMb2MsIDEtcmVsTG9jKSwKICAgICAgICAgYmluID0gY3V0KGZvbGQucmVsTG9jLCBicmVha3MgPSBmcmVxLmJpbnMsIGxhYmVscyA9IGZyZXEubGFiZWwpKQoKIyBhZGQgdGhlIGhvbW9sb2dzCmZnLmZyZXEgPC0gZmcuZnJlcSAlPiUgCiAgbXV0YXRlKGZvbGQucmVsTG9jID0gaWZlbHNlKHJlbExvYyA8PSAwLjUsIHJlbExvYywgMS1yZWxMb2MpLAogICAgICAgICBiaW4gPSBjdXQoZm9sZC5yZWxMb2MsIGJyZWFrcyA9IGZyZXEuYmlucywgbGFiZWxzID0gZnJlcS5sYWJlbCkpIApmcmVxLnBsb3QgPC0gZmcuZnJlcSAlPiUKICBtdXRhdGUoY2hyb21vc29tZSA9ICJIaWwiKSAlPiUgICMgd2UgbGFiZWwgdGhlIGhvbW9sb2dzIGFzIEhpbCB0byBtYWtlIGl0IGEgc2VwYXJhdGUgY2xhc3MKICBzZWxlY3Qoc3BlY2llcyA9IHNwZWNpZXMsIGNocm9tb3NvbWUsIGJpbikgJT4lIAogIGJpbmRfcm93cyhzZWxlY3QoYmcuZnJlcS50Yiwgc3BlY2llcywgY2hyb21vc29tZSwgYmluKSkgJT4lIAogIG11dGF0ZShjaHJvbW9zb21lID0gb3JkZXJlZChjaHJvbW9zb21lLCBsZXZlbHMgPSBjKDE6MTIsTEVUVEVSUywiSGlsIikpKSAlPiUgCiAgZ3JvdXBfYnkoc3BlY2llcykgJT4lIAogIGZpbHRlcihzdW0oY2hyb21vc29tZSA9PSAiSGlsIikgPj0zKSAjIHJlbW92ZSBzcGVjaWVzIHRoYXQgaGF2ZSBmZXdlciB0aGFuIDMgSGlsIGhvbW9sb2dzCmBgYAoKYGBge3J9CiMgcGxvdApmcmVxLnBsb3QgJT4lIAogICNtdXRhdGUoc3BlY2llcyA9IHBhc3RlMChzdWJzdHIoc3BlY2llcywgMSwgMSksICIuICIsIHN1YnN0cihzcGVjaWVzLCAyLCAxNSkpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gY2hyb21vc29tZSwgZ3JvdXAgPSBiaW4sIGZpbGwgPSBiaW4pKSArIAogIGdlb21fYmFyKHBvc2l0aW9uID0gcG9zaXRpb25fZmlsbCgpKSArCiAgZmFjZXRfd3JhcCh+IHNwZWNpZXMsIHNjYWxlcyA9ICJmcmVlX3giLCApICsgCiAgI3NjYWxlX2ZpbGxfYnJld2VyKCJEaXN0YW5jZSBmcm9tXG5jaHJvbW9zb21lIGVuZCIsIHR5cGUgPSAicXVhbCIsIHBhbGV0dGUgPSAzKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2QoZGlyZWN0aW9uID0gLTEsIGVuZCA9IDAuOTUsIGFscGhhID0gMC45KSArCiAgc2NhbGVfeV9jb250aW51b3VzKG5hbWUgPSAiQ3VtdWxhdGl2ZSAlIG9mIGdlbmVzIiwgdHJhbnMgPSAicmV2ZXJzZSIsIGJyZWFrcyA9IHNlcSgwLDEsMC4yKSkgKyAKICB0aGVtZV9jb3dwbG90KCkgKyBwYW5lbF9ib3JkZXIoY29sb3IgPSAiZ3JleTgwIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoZmFjZSA9IDMpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDAuNykpKQoKZ2dzYXZlKCIuLi9vdXRwdXQvaW1nLzIwMjIwOTIwLWNvbXBhcmUtaG9tb2xvZ3MtY2hyb21vc29tYWwtbG9jYXRpb25zLXRvLWJnLnBuZyIsIHdpZHRoID0gNywgaGVpZ2h0ID0gNCkKYGBgCkluIHRoZSBwbG90IGFib3ZlLCB3ZSBjYW4gc2VlIHRoYXQgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgSGlsIHByb3RlaW5zIG9uIHRoZSBjaHJvbW9zb21lIGRldmlhdGUgZnJvbSB0aGUgYmFja2dyb3VuZC4gT25seSBzcGVjaWVzIHdpdGggdGhyZWUgb3IgbW9yZSBIaWwgZmFtaWx5IG1lbWJlcnMgYXJlIHNob3duIGhlcmUuCgpOb3cgdGhhdCB3ZSBoYXZlIHRoZSBiYWNrZ3JvdW5kIGdlbmUgZnJlcXVlbmNpZXMgY29tcHV0ZWQsIHdlIGNhbiBzdGFydCBjb25zdHJ1Y3RpbmcgYSB0ZXN0IHRoYXQgdGVzdHMgZm9yIHNpZ25pZmljYW50IGRlcGFydHVyZSBpbiB0aGUgY2hyb21vc29tYWwgbG9jYXRpb25zIG9mIG91ciBwcm90ZWluIGZhbWlseSBmcm9tIHRoZSBiYWNrZ3JvdW5kIGZyZXF1ZW5jaWVzLiBPbmUgaWRlYSBpcyB0byBkaXZpZGUgdGhlIGNocm9tb3NvbWUgaW50byBlcXVhbC1zaXplZCBiaW5zIGFuZCB1c2UgdGhlIGZyZXF1ZW5jaWVzIG9mIF9hbGxfIGdlbmVzIGluIGVhY2ggYmluIGFzIHRoZSBtdWx0aW5vbWlhbCBwcm9iYWJpbGl0aWVzIGluIHRoZSBudWxsIGh5cG90aGVzaXMuIElmIG91ciBwcm90ZWlucyB3ZXJlIHJhbmRvbWx5IHNlbGVjdGVkIGZyb20gZWFjaCBjaHJvbW9zb21lIHdpdGhvdXQgcmVnYXJkIHRvIHRoZWlyIGxvY2F0aW9uLCB3ZSB3b3VsZCBleHBlY3QgdGhlaXIgbG9jYXRpb25zIHRvIGNvbmZvcm0gdG8gdGhlIGJhY2tncm91bmQgZnJlcXVlbmNpZXMuIFRoaXMgY2FuIGJlIHRlc3RlZCB1c2luZyBhbiBleGFjdCBtdWx0aW5vbWlhbCB0ZXN0IG9yIGFuIGFwcHJveGltYXRlIENoaS1zcXVhcmUgdGVzdCBvciBHLXRlc3QuIFNpbmNlIHdlIGRvbid0IGRpc3Rpbmd1aXNoIHRoZSB0d28gZW5kcyBvZiBhIGNocm9tb3NvbWUsIHdlIGNhbiAiZm9sZCIgdGhlIGNocm9tb3NvbWUgImluIGhhbGYiIGFuZCBtZWFzdXJlIGVhY2ggZ2VuZSdzIGxvY2F0aW9uIGFzIGEgcGVyY2VudGFnZSBmcm9tIHRoZSBjbG9zZXIgZW5kLCBpLmUuIHRoZSByZWxhdGl2ZSBsb2NhdGlvbiByYW5naW5nIGZyb20gMCUtNTAlLiBJZiB3ZSBjYW4gcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMsIHRoYXQgY29uc3RpdHV0ZXMgZXZpZGVuY2UgdGhhdCB0aGUgcHJvdGVpbnMgZnJvbSBvdXIgZ3JvdXAgYXJlIG5vdCByYW5kb21seSBzZWxlY3RlZCBmcm9tIHRoZSBiYWNrZ3JvdW5kIHNldC4KCioqUmVzdWx0IG9mIG11bHRpbm9taWFsIHRlc3QqKgoKYGBge3IgbXVsdGlub21pYWxfdGVzdH0KIyBpbnN0YWxsIFhOb21pYWwgcGFja2FnZSBmb3IgdGhlIG11bHRpbm9taWFsIGV4YWN0IHRlc3QgZnVuY3Rpb24KIyBodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvWE5vbWlhbC92aWduZXR0ZXMvWE5vbWlhbC5odG1sI2UxCndoaWxlKCFyZXF1aXJlKFhOb21pYWwpKQogIHN1cHByZXNzTWVzc2FnZXMoaW5zdGFsbC5wYWNrYWdlcygiWE5vbWlhbCIpKQojIGNhbGN1bGF0ZSBwb29sZWQgYmFja2dyb3VuZCBmcmVxdWVuY3kKYmcuY250IDwtIHRhYnVsYXRlKGJnLmZyZXEudGIkYmluKQpmZy5jbnQgPC0gdGFidWxhdGUoZmcuZnJlcSRiaW4pCnhtdWx0aShvYnMgPSBmZy5jbnQsIGV4cHIgPSBiZy5jbnQsIGRldGFpbCA9IDMpCmBgYApOb3RlIHRoYXQgdGhlIHRocmVlIF9QXy12YWx1ZXMgY29ycmVzcG9uZCB0byB0aHJlZSBhcHByb2FjaGVzIG9mIHRlc3RpbmcgdGhlIGdvb2RuZXNzLW9mLWZpdC4gVGhlIExMUiwgd2hpY2ggc3RhbmRzIGZvciBMb2cgTGlrZWxpaG9vZCBSYXRpbywgaXMgZ2VuZXJhbGx5IHByZWZlcnJlZC4gQnV0IGFsbCB0aHJlZSBzYWlkIHRoZSBzYW1lIHRoaW5nOiB0aGUgb2JzZXJ2YXRpb24gZGV2aWF0ZXMgZnJvbSB0aGUgYmFja2dyb3VuZCBmcmVxdWVuY3kgc2lnbmlmaWNhbnRseS4gQnkgbG9va2luZyBhdCB0aGUgcGxvdHMgYWJvdmUsIGl0IGlzIGNsZWFyIHRoYXQgdGhlIGRldmlhdGlvbiBpcyBkdWUgdG8gdGhlIGV4Y2VzcyBvZiBvdXIgaG9tb2xvZ3MgcmVzaWRpbmcgaW4gdGhlIDAtMTAlIGJpbiwgd2hpY2ggaXMgdGhlIHRpcCBvZiB0aGUgY2hyb21vc29tZXMuCgpUaGUgdGVzdCBhYm92ZSBhc3N1bWVzIHRoYXQgdGhlIGdlbmUgZGVuc2l0eSBhbG9uZyBhbGwgY2hyb21vc29tZXMgaW4gdGhlIGVpZ2h0IHNwZWNpZXMgZm9sbG93IHRoZSBzYW1lIGRpc3RyaWJ1dGlvbi4gVGhlIGVtcGlyaWNhbCBvYnNlcnZhdGlvbiBzdXBwb3J0cyB0aGF0IGh5cG90aGVzaXMuIFNob3VsZCB0aGF0IHRvIGJlIG5vdCB0aGUgY2FzZSwgd2UgY291bGQgYWxzbyBhY2NvdW50IGZvciB0aGUgdmFyaWFiaWxpdHkgaW4gZ2VuZSBkZW5zaXR5IGRpc3RyaWJ1dGlvbiBiZXR3ZWVuIHNwZWNpZXMgb3IgZXZlbiBiZXR3ZWVuIGNocm9tb3NvbWVzIHdpdGhpbiBhIHNwZWNpZXMuIFRoZSBpZGVhIGlzIHRvIGZpcnN0IGNvbGxlY3QgdGhlIGNocm9tb3NvbWVzIHRoYXQgb3VyIGhvbW9sb2dzIGNvbWUgZnJvbSwgYW5kIHRoZW4gcmFuZG9tbHkgc2FtcGxlIHRoZSAqKnNhbWUqKiBudW1iZXIgb2YgZ2VuZXMgYXMgdGhlIG51bWJlciBvZiBvdXIgaG9tb2xvZ3Mgb24gdGhhdCBjaHJvbW9zb21lLiBEbyB0aGlzIGZvciBhbGwgb2YgdGhlIGhvbW9sb2ctY29udGFpbmluZyBjaHJvbW9zb21lcywgd2Ugd291bGQgb2J0YWluIG9uZSByYW5kb20gc2FtcGxlLiBSZXBlYXQgdGhpcyBwcm9jZXNzIDEwMDAgdGltZXMgb3IgbW9yZSwgd2Ugd2lsbCB0aGVuIGdldCB0aGUgcHNldWRvc2FtcGxlLCB3aGljaCB3ZSBjYW4gdXNlIHRvIGNvbXBhcmUgd2l0aCBvdXIgb2JzZXJ2YXRpb25zLiBIZXJlIHdlIG5lZWQgdG8gY29tZSB1cCB3aXRoIGEgc3RhdGlzdGljIHRoYXQgc3VtbWFyaXplcyBlYWNoIG9mIG91ciBvYnNlcnZhdGlvbiBvciBwc2V1ZG9zYW1wbGUuIEZvciBleGFtcGxlLCB3ZSBjb3VsZCBjYWxjdWxhdGUgdGhlIG1lZGlhbiAlIGxvY2F0aW9uIGZvciBlYWNoIHNhbXBsZSwgYW5kIGFzayB3aGVyZSBvdXIgb2JzZXJ2YXRpb24gbGllIHJlbGF0aXZlIHRvIHRoZSBwc2V1ZG9zYW1wbGVzLiBJJ2xsIHNraXAgdGhpcyBhcHByb2FjaCBmb3Igbm93IHNpbmNlIHRoZSBmaXJzdCBhcHByYW9jaCBhcHBlYXJzIHRvIGJlIE9LIGdpdmVuIHRoZSBzaW1pbGFyIGdlbmUgZGVuc2l0eSBkaXN0cmlidXRpb24gYWNyb3NzIGNocm9tb3NvbWVzIGFuZCBzcGVjaWVzLg==